Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
S
SOAAP
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Martin Streitenberger
SOAAP
Commits
3a4e0c04
Commit
3a4e0c04
authored
3 years ago
by
RobertPatzke
Browse files
Options
Downloads
Patches
Plain Diff
Library BlePoll added
parent
bb4474ee
Branches
Branches containing commit
No related tags found
No related merge requests found
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
libraries/BlePoll/BlePoll.cpp
+1261
-0
1261 additions, 0 deletions
libraries/BlePoll/BlePoll.cpp
libraries/BlePoll/BlePoll.h
+372
-0
372 additions, 0 deletions
libraries/BlePoll/BlePoll.h
with
1633 additions
and
0 deletions
libraries/BlePoll/BlePoll.cpp
0 → 100644
+
1261
−
0
View file @
3a4e0c04
//-----------------------------------------------------------------------------
// Thema: Social Manufacturing Network / Development Environment
// Datei: BlePoll.cpp
// Editor: Robert Patzke
// URI/URL: www.mfp-portal.de
//-----------------------------------------------------------------------------
// Lizenz: CC-BY-SA (wikipedia: Creative Commons)
// Datum: 1. September 2021
//
// Diese Bibliothek (Klassse) enthält diverse Ressourcen zur Kommunikation
// über BLE-Funkmodule auf niedriger Ebene, also dem direkten Telegrammaustausch.
// Darauf aufbauend sollen mehrkanalige Messeinrichtungen mit möglichst
// geringen Latenzzeiten entwickelt werden.
//
#include
"BlePoll.h"
// --------------------------------------------------------------------------
// Textmakros zur Vereinfachung der Programmierung
// --------------------------------------------------------------------------
#define next(x) nextState = &BlePoll::x
// --------------------------------------------------------------------------
// Initialisierungen
// --------------------------------------------------------------------------
BlePoll
::
BlePoll
(
IntrfRadio
*
refRadio
,
dword
inCycleMics
)
{
init
(
refRadio
,
inCycleMics
,
NULL
);
}
BlePoll
::
BlePoll
(
IntrfRadio
*
refRadio
,
MicsecFuPtr
inMicroFu
)
{
init
(
refRadio
,
0
,
inMicroFu
);
}
void
BlePoll
::
init
(
IntrfRadio
*
refRadio
,
dword
inCycleMics
,
MicsecFuPtr
inMicroFu
)
{
radio
=
refRadio
;
radio
->
setPacketParms
(
bptAdv
);
radio
->
setAccessAddress
(
AdvAccAddr
);
chn
=
adr
=
area
=
0
;
master
=
nak
=
eadr
=
false
;
plMode
=
plmIdle
;
plpType
=
plptEmpty
;
micSec
=
inMicroFu
;
cycleMics
=
inCycleMics
;
cycleCnt
=
0
;
toValue
=
0
;
toSet
=
0
;
nextState
=
NULL
;
slaveIdx
=
0
;
pollIdx
=
0
;
pollNr
=
0
;
maxAdr
=
MAXSLAVE
;
curSlave
=
NULL
;
cntAlien
=
0
;
cntWrong
=
0
;
cntAllNaks
=
0
;
cntWaitDisabled
=
0
;
cntPolling
=
0
;
cntAllRecs
=
0
;
cntAllTo
=
0
;
pollStopped
=
false
;
pollStop
=
false
;
runCounter
=
0
;
newValue
=
false
;
cbData
=
NULL
;
for
(
int
i
=
1
;
i
<=
MAXSLAVE
;
i
++
)
{
slaveList
[
i
].
cntNakEP
=
0
;
slaveList
[
i
].
cntTo
=
0
;
slaveList
[
i
].
pIdx
=
0
;
slaveList
[
i
].
delayCnt
=
10
;
pollList
[
i
].
prioCnt
=
0
;
pollList
[
i
].
slIdx
=
0
;
pollList
[
i
].
status
=
0
;
}
}
// ----------------------------------------------------------------------------
void
BlePoll
::
begin
(
ComType
typeIn
,
int
adrIn
,
AppType
appType
,
dword
watchDog
)
{
// TODO
// --------------------------------------------------------------------------
// Das muss nochmal völlig neu überarbeitet werden.
// Zur Zeit sind viele Redundanzen und teilweise Mehrdeutigkeiten enthalten,
// weil für jede Testanwendung spezifische Vorbereitungen gemacht wurden.
// --------------------------------------------------------------------------
//
wdTimeOut
=
watchDog
;
// WatchDog-Time-Out in Mikrosekunden
if
(
typeIn
==
ctMASTER
)
master
=
true
;
else
master
=
false
;
void
resetPollCounters
();
chn
=
0
;
// 1. Bewerbungskanal
area
=
0
;
// Default-Anwendungsbereich
eadr
=
true
;
// Start mit leerem Polling
// --------------------------------------------------------------------------
plMode
=
plmEmpty
;
// Leeres Polling (Adressenliste)
// --------------------------------------------------------------------------
if
(
master
)
{
nak
=
true
;
// Nak-Bit vom Master forciert leere Antwort
maxAdr
=
adrIn
;
if
(
maxAdr
>
MAXSLAVE
)
maxAdr
=
MAXSLAVE
;
adr
=
1
;
slaveIdx
=
adr
;
// Reserve für getrennte Verwaltung von adr und slaveIdx
next
(
smInit
);
}
else
{
nak
=
true
;
adr
=
adrIn
;
next
(
smInit
);
}
if
(
appType
==
atSOAAP
||
appType
==
atTestSend
)
{
pduOut
.
adr5
=
0x53
;
pduOut
.
adr4
=
0x4F
;
pduOut
.
adr3
=
0x41
;
pduIn
.
adr5
=
0x53
;
pduIn
.
adr4
=
0x4F
;
pduIn
.
adr3
=
0x41
;
}
if
(
appType
==
atTestSend
)
plMode
=
plmTest
;
pduOut
.
head
=
HeadS0B
;
pduIn
.
head
=
HeadS0B
;
pduOut
.
data
[
0
]
=
0
;
// Pdu-Zähler (CNT)
pduIn
.
data
[
0
]
=
0
;
pduOut
.
data
[
1
]
=
appType
;
// Pdu-Typ (TYPE)
pduIn
.
data
[
1
]
=
appType
;
if
(
appType
==
atSOAAP
)
{
if
(
master
)
{
valuePdu
.
appId
=
plptMeas6
;
plMode
=
plmSoaapM
;
fullCycle
=
true
;
}
else
{
valuePdu
.
appId
=
plptMeas6
;
plMode
=
plmSoaapS
;
//plMode = plmSoaapM;
}
}
valuePdu
.
measCnt
=
0
;
valuePdu
.
counter
=
0
;
valuePdu
.
type
=
appType
;
}
// --------------------------------------------------------------------------
// Konfiguration
// --------------------------------------------------------------------------
//
void
BlePoll
::
setPollAddress
(
int
chnIn
,
int
adrIn
,
int
areaIn
,
bool
masterIn
,
bool
eadrIn
,
bool
nakIn
)
{
chn
=
chnIn
;
adr
=
adrIn
;
area
=
areaIn
;
master
=
masterIn
;
eadr
=
eadrIn
;
nak
=
nakIn
;
}
void
BlePoll
::
setPduAddress
()
{
setPduAddress
(
&
pduOut
);
}
void
BlePoll
::
setPduAddress
(
bcPduPtr
pduPtr
)
{
pduPtr
->
adr0
=
(
byte
)
adr
;
pduPtr
->
adr1
=
(
byte
)
(
area
&
0x3F
);
if
(
nak
)
pduPtr
->
adr1
|=
0x40
;
if
(
eadr
)
pduPtr
->
adr1
|=
0x80
;
pduPtr
->
adr2
=
(
byte
)
chn
;
if
(
master
)
pduPtr
->
adr2
|=
0x80
;
}
void
BlePoll
::
setEmptyPollParams
(
int
cycleTotal
,
int
cycleRun
,
dword
timeOut
)
{
epCycleTotal
=
cycleTotal
;
epCycleRun
=
cycleRun
;
epTimeOut
=
timeOut
;
}
void
BlePoll
::
setDataPollParams
(
int
slAdr
,
int
prio
,
int
minPrio
,
dword
timeOut
)
{
if
(
slAdr
>
MAXSLAVE
)
return
;
slaveList
[
slAdr
].
prioSet
=
prio
;
slaveList
[
slAdr
].
minPrio
=
minPrio
;
slaveList
[
slAdr
].
timeOut
=
timeOut
;
}
void
BlePoll
::
setCbDataPtr
(
cbDataPtr
cbPtr
)
{
cbData
=
cbPtr
;
}
// --------------------------------------------------------------------------
// Hilfsfunktionen
// --------------------------------------------------------------------------
//
void
BlePoll
::
setTimeOut
(
dword
value
)
{
if
(
micSec
!=
NULL
)
{
toSet
=
micSec
();
toValue
=
value
;
}
else
{
if
(
cycleMics
>
1
)
cycleCnt
=
value
/
cycleMics
;
else
cycleCnt
=
value
;
}
}
bool
BlePoll
::
timeOut
()
{
if
(
micSec
!=
NULL
)
{
if
((
micSec
()
-
toSet
)
>
toValue
)
return
(
true
);
else
return
(
false
);
}
else
{
if
(
cycleCnt
>
0
)
return
(
false
);
else
return
(
true
);
}
}
bool
BlePoll
::
getValues
(
bcPduPtr
pduPtr
)
{
bool
retv
=
false
;
pduPtr
->
len
=
28
;
pduPtr
->
data
[
0
]
++
;
// Pdu-Counter
pduPtr
->
data
[
1
]
=
valuePdu
.
type
;
pduPtr
->
data
[
2
]
=
valuePdu
.
appId
;
newValue
=
cbData
(
plptMeas6
,
&
pduPtr
->
data
[
4
]);
if
(
newValue
)
{
retv
=
true
;
pduPtr
->
data
[
3
]
++
;
// measCnt
}
return
(
retv
);
}
// --------------------------------------------------------------------------
// Steuerung des Polling
// --------------------------------------------------------------------------
//
// Aktuellen Betriebszustand einstellen
//
void
BlePoll
::
start
(
PlMode
inPlMode
)
{
oldPlMode
=
plMode
;
plMode
=
inPlMode
;
pollStop
=
true
;
}
// Anhalten des leeren Polling
//
void
BlePoll
::
stopEP
()
{
pollStop
=
true
;
}
// Weiterlaufen des leeren Polling
//
void
BlePoll
::
resumeEP
()
{
pollStop
=
false
;
pollStopped
=
false
;
}
// Abfrage, ob gestoppt
//
bool
BlePoll
::
stoppedEP
()
{
return
(
pollStopped
);
}
// Eintritt in die Zustandsmaschine
//
void
BlePoll
::
run
()
{
runCounter
++
;
if
(
cycleCnt
>
0
)
cycleCnt
--
;
if
(
nextState
!=
NULL
)
(
this
->*
nextState
)();
}
// --------------------------------------------------------------------------
// Zugriff auf Polling-Informationen
// --------------------------------------------------------------------------
//
int
BlePoll
::
getSlaveList
(
byte
*
dest
,
int
maxByte
)
{
int
slIdx
;
for
(
int
i
=
1
;
i
<=
pollMaxNr
;
i
++
)
{
if
(
i
==
maxByte
)
break
;
slIdx
=
pollList
[
i
].
slIdx
;
dest
[
i
-
1
]
=
slaveList
[
slIdx
].
adr
;
}
return
(
pollMaxNr
);
}
void
BlePoll
::
resetPollCounters
()
{
int
slIdx
;
SlavePtr
slPtr
;
for
(
int
i
=
1
;
i
<=
pollMaxNr
;
i
++
)
{
slIdx
=
pollList
[
i
].
slIdx
;
slPtr
=
&
slaveList
[
slIdx
];
slPtr
->
cntAckDP
=
0
;
slPtr
->
cntErrCrc
=
0
;
slPtr
->
cntLostMeas
=
0
;
slPtr
->
cntLostPdu
=
0
;
slPtr
->
cntNakEP
=
0
;
slPtr
->
cntTo
=
0
;
}
}
// ****************************************************************************
// Zustandsmaschine
// ****************************************************************************
//
// ----------------------------------------------------------------------------
// Verzweigung nach Anwendung (nach Anlauf)
// ----------------------------------------------------------------------------
//
dword
smInitCnt
;
void
BlePoll
::
smInit
()
{
bleState
=
100
;
smInitCnt
++
;
switch
(
plMode
)
{
case
plmIdle
:
break
;
case
plmTest
:
next
(
smStartTest
);
break
;
case
plmEmpty
:
epCycleTotal
=
-
1
;
epCycleRun
=
-
1
;
next
(
smStartEP
);
break
;
case
plmScan
:
break
;
case
plmSoaapM
:
if
(
pollStop
)
pollStopped
=
true
;
if
(
!
pollStopped
)
next
(
smStartEP
);
break
;
case
plmSoaapS
:
next
(
smStartComES
);
break
;
case
plmXchg
:
break
;
}
}
// ----------------------------------------------------------------------------
// Verzweigung nach Anwendung (im Betrieb)
// ----------------------------------------------------------------------------
//
dword
smIdleCnt
;
void
BlePoll
::
smIdle
()
{
bleState
=
200
;
smIdleCnt
++
;
switch
(
plMode
)
{
case
plmIdle
:
break
;
case
plmTest
:
next
(
smStartTest
);
break
;
case
plmEmpty
:
next
(
smStartEP
);
break
;
case
plmScan
:
if
(
master
)
next
(
smReqComS
);
break
;
case
plmXchg
:
if
(
!
master
)
next
(
smStartComES
);
break
;
case
plmSoaapM
:
if
(
!
pollStopped
)
next
(
smStartEP
);
break
;
}
}
// ----------------------------------------------------------------------------
// Low Level Tests
// ----------------------------------------------------------------------------
//
void
BlePoll
::
smStartTest
()
{
bleState
=
500
;
if
(
master
)
{
nak
=
false
;
adr
=
1
;
slaveIdx
=
adr
;
setTimeOut
(
500000
);
}
else
{
nak
=
true
;
}
pduOut
.
len
=
6
;
setPduAddress
();
radio
->
setChannel
(
chn
);
next
(
smWaitTest
);
}
void
BlePoll
::
smWaitTest
()
{
if
(
!
timeOut
())
return
;
radio
->
disable
(
txmRead
);
next
(
smLoopTest
);
}
void
BlePoll
::
smLoopTest
()
{
pduOut
.
adr0
++
;
radio
->
send
(
&
pduOut
,
txmRead
);
setTimeOut
(
500000
);
next
(
smWaitTest
);
}
// ----------------------------------------------------------------------------
// L e e r e s P o l l i n g
// ----------------------------------------------------------------------------
//
void
BlePoll
::
smStartEP
()
{
bleState
=
1000
;
pduOut
.
len
=
6
;
// Nur Adresse
radio
->
setChannel
(
chn
);
pollMaxNr
=
0
;
nak
=
true
;
if
(
master
)
{
adr
=
1
;
slaveIdx
=
adr
;
// Slave-Array[0] reserviert
pollIdx
=
1
;
// Poll-Array[0] reserviert
pollNr
=
0
;
// Anzahl in der Poll-Liste
next
(
smReqEadr
);
}
else
{
next
(
smWaitEadr
);
}
}
// ----------------------------------------------------------------------------
// Leeres Polling M a s t e r
// ----------------------------------------------------------------------------
//
void
BlePoll
::
smReqEadr
()
{
bleState
=
1100
;
// Datenstruktur für den Slave definieren
//
curSlave
=
&
slaveList
[
slaveIdx
];
// Zeiger auf zu pollenden Slave
curSlave
->
adr
=
adr
;
curSlave
->
area
=
area
;
curSlave
->
chn
=
chn
;
curPoll
=
&
pollList
[
pollIdx
];
// Zeiger auf freien Platz in Poll-Liste
setPduAddress
();
setTimeOut
(
epTimeOut
);
radio
->
getStatistics
(
&
statistic
);
radio
->
send
(
&
pduOut
,
txmPoll
);
cntPolling
++
;
next
(
smWaitNak
);
}
void
BlePoll
::
smWaitNak
()
{
bleState
=
1110
;
if
(
timeOut
())
{
// Für die Adresse ist kein Teilnehmer vorhanden, oder die Übertragung ist gestört
//
radio
->
disable
(
txmPoll
);
if
(
curSlave
->
pIdx
!=
0
)
{
// Wenn der Teilnehmer bereits in die Poll-Liste eingetragen ist
// dann wird darin seine temporäre Abwesenheit markiert
pollList
[(
int
)
curSlave
->
pIdx
].
status
&=
~
psSlaveIsPresent
;
}
// Der Time-Out-Zähler macht erkenntlich, wie stark sich Störungen auswirken
//
curSlave
->
cntTo
++
;
cntAllTo
++
;
// Nächste Adresse und zur Anforderung
//
adr
++
;
slaveIdx
=
adr
;
if
(
adr
>
maxAdr
)
next
(
smEndEP
);
else
next
(
smReqEadr
);
return
;
}
if
(
radio
->
fin
(
txmPoll
,
&
crcError
))
{
// Auf dem Kanal wurde ein Datensatz (BLE-Beacon) empfangen
// und es werden die ersten 8 Byte (Header, Len und Adresse) geholt
//
cntAllRecs
++
;
radio
->
getRecData
(
&
pduIn
,
8
);
if
(
pduIn
.
adr3
!=
pduOut
.
adr3
||
pduIn
.
adr4
!=
pduOut
.
adr4
||
pduIn
.
adr5
!=
pduOut
.
adr5
)
{
// Wenn die höherwertigen 3 Byte der Adresse nicht mit der Anwendungskodierung
// übereinstimmen, dann ist es ein Fremd-Beacon.
// Diese werden gezählt und kennzeichnen, wie stark aktiv ein anderes
// BLE-Netzwerk in Reichweite ist.
//
cntAlien
++
;
// Nächste Adresse und zur Anforderung, nicht auf Time-Out warten
//
adr
++
;
slaveIdx
=
adr
;
if
(
adr
>
maxAdr
)
next
(
smEndEP
);
else
next
(
smReqEadr
);
return
;
}
if
(
pduIn
.
adr0
!=
pduOut
.
adr0
||
(
pduIn
.
adr1
&
0x3F
)
!=
(
pduOut
.
adr1
&
0x3F
))
{
// Wenn die Teinehmernummer oder die Gebietsnummer falsch sind, dann ist
// möglicherweise ein weiterer Master aktiv, der fehlerhafterweise denselben
// Kanal verwendet.
// Auch dieses Ereignis wird gezäht.
cntWrong
++
;
// Nächste Adresse und zur Anforderung, nicht auf Time-Out warten
//
adr
++
;
slaveIdx
=
adr
;
if
(
adr
>
maxAdr
)
next
(
smEndEP
);
else
next
(
smReqEadr
);
return
;
}
// Alles korrekt, der adressierte Teilnehmer hat rechtzeitig geantwortet
// Radio ist abgeschaltet
//
if
(
curSlave
->
pIdx
!=
0
)
{
// Wenn der Teilnehmer bereits in die Poll-Liste eingetragen ist,
// dann wird er darin als aktuell anwesend markiert
//
pollList
[(
int
)
curSlave
->
pIdx
].
status
|=
psSlaveIsPresent
;
pollNr
++
;
}
else
{
// Wenn nicht, wird der aktuelle Listeneintrag definiert
//
curPoll
->
status
|=
psSlaveIsPresent
|
psSlaveWasPresent
;
curPoll
->
slIdx
=
slaveIdx
;
// Querverweis zur Liste möglicher Teilnehmer
curSlave
->
pIdx
=
pollIdx
;
// Und in der Liste auch ein Verweis zur Poll-Liste
pollIdx
++
;
// Weiter mit nächstem Listenplatz
pollNr
++
;
// Anzahl der beantworteten Pollings
}
// Die Nak-Antworten werden gezählt
//
curSlave
->
cntNakEP
++
;
// Teilnehmerspezifisch
cntAllNaks
++
;
// und insgesamt
// Weiter mit nächstem Teilnehmer und nächster Adresse (TN-Nummer)
//
adr
++
;
slaveIdx
=
adr
;
// Wenn die vorgegeben Endadresse erreicht ist
// dann zum Ende des Polldurchgangs über alle möglichen Teilnehmer,
// ansonsten nächsten Teilnehmer pollen
//
if
(
adr
>
maxAdr
)
next
(
smEndEP
);
else
next
(
smReqEadr
);
}
}
void
BlePoll
::
smEndEP
()
{
// Nach jedem vollständigen Polldurchlauf kann das Polling
// abgebrochen werden.
//
if
(
pollStop
||
pollStopped
)
{
pollStopped
=
true
;
next
(
smIdle
);
return
;
}
// Es werden die Maximalwerte der rechtzeitigen Antworten gebildet
//
if
(
pollNr
>
pollMaxNr
)
pollMaxNr
=
pollNr
;
if
(
pollMaxNr
==
0
)
{
// Wenn noch kein Teilnehmer angeschlossen ist (oder Kanal total gestört)
//
if
(
epCycleTotal
>
0
)
{
// dann wird der Pollvorgang so oft wie vorgegeben wiederholt
//
epCycleTotal
--
;
pollNr
=
0
;
pollIdx
=
1
;
adr
=
1
;
slaveIdx
=
adr
;
next
(
smReqEadr
);
return
;
}
else
if
(
epCycleTotal
==
0
)
{
// und anschließend der Idle-Zustand angenommen
next
(
smIdle
);
return
;
}
}
else
{
// Wenn wenigstens schon ein Teilnehmer geantwortet hat
//
if
(
epCycleRun
>
0
)
{
// dann wird der Pollvorgang auch so oft wie anderweitig vorgegeben wiederholt
//
epCycleRun
--
;
pollNr
=
0
;
//pollIdx = 1; falsch, pollIdx zeigt auf nächsten freien Platz
adr
=
1
;
slaveIdx
=
adr
;
next
(
smReqEadr
);
return
;
}
else
if
(
epCycleRun
==
0
)
{
// und anschließend die Datenübertragung gestartet
// oder das Polling ganz beendet
//
if
(
fullCycle
)
next
(
smStartCom
);
else
next
(
smIdle
);
return
;
}
}
// Nächster Poll-Lauf, wenn epCycleXXX noch nicht abgelaufen ist
// oder auf einen wert kleiner 0 gestellt wurde
//
pollNr
=
0
;
//pollIdx = 1; falsch, pollIdx zeigt auf nächsten freien Platz
adr
=
1
;
slaveIdx
=
adr
;
next
(
smReqEadr
);
}
// ----------------------------------------------------------------------------
// Leeres Polling S l a v e
// ----------------------------------------------------------------------------
//
void
BlePoll
::
smWaitEadr
()
{
bleState
=
1200
;
if
(
!
radio
->
disabled
(
txmRespE
))
{
radio
->
disable
(
txmRespE
);
cntWaitDisabled
++
;
return
;
}
setPduAddress
();
radio
->
send
(
&
pduOut
,
txmRespE
);
next
(
smEvalPoll
);
}
void
BlePoll
::
smEvalPoll
()
{
bleState
=
1210
;
radio
->
getStatistics
(
&
statistic
);
if
(
!
radio
->
fin
(
txmRespE
,
&
crcError
))
return
;
next
(
smWaitEadr
);
}
// ----------------------------------------------------------------------------
// D a t e n ü b e r t r a g u n g
// ----------------------------------------------------------------------------
//
void
BlePoll
::
smStartCom
()
{
bleState
=
2000
;
if
(
pollStop
)
// Der Start der Datenübertragung kann
{
// verzögert werden
pollStopped
=
true
;
return
;
}
pduOut
.
len
=
6
;
radio
->
setChannel
(
chn
);
if
(
master
)
{
for
(
int
i
=
1
;
i
<=
pollMaxNr
;
i
++
)
{
int
slIdx
=
pollList
[
i
].
slIdx
;
pollList
[
i
].
prioCnt
=
slaveList
[
slIdx
].
prioSet
;
}
nak
=
false
;
pollIdx
=
1
;
next
(
smReqComS
);
}
else
{
nak
=
true
;
next
(
smWaitEadr
);
}
}
// ----------------------------------------------------------------------------
// Datenübertragung Master S l a v e - > M a s t e r
// ----------------------------------------------------------------------------
//
void
BlePoll
::
smReqComS
()
{
bleState
=
2100
;
if
(
pollStop
)
// Das Polling kann
{
// angehalten werden
pollStopped
=
true
;
return
;
}
if
(
!
radio
->
disabled
(
txmPoll
))
{
radio
->
disable
(
txmPoll
);
return
;
}
// Der aufzufordernde Teilnehmer wird der Poll-Liste entnommen
//
curPoll
=
&
pollList
[
pollIdx
];
// Ein Aufruf erfolgt nur, wenn der Prioritätszähler auf 0 steht
// ansonsten wird er dekrementiert und der nächste Teilnehmer
// im nächsten Zustandslauf ausgewählt.
//
if
(
curPoll
->
prioCnt
>
0
)
{
curPoll
->
prioCnt
--
;
pollIdx
++
;
if
(
pollIdx
>
pollMaxNr
)
pollIdx
=
1
;
return
;
}
// Zugriff auf den Slave aus der Poll-Liste vorbereiten
//
slaveIdx
=
curPoll
->
slIdx
;
curSlave
=
&
slaveList
[
slaveIdx
];
// Slave-spezifische Parameter setzen
//
eadr
=
false
;
nak
=
false
;
adr
=
curSlave
->
adr
;
area
=
curSlave
->
area
;
setPduAddress
();
setTimeOut
(
curSlave
->
timeOut
);
// Statistic-Daten einholen für evt. Auswertung
//
radio
->
getStatistics
(
&
statistic
);
// Aufruf des Slave starten
//
radio
->
send
(
&
pduOut
,
txmPoll
);
cntPolling
++
;
next
(
smWaitAckComS
);
}
int
tmpInt1
,
tmpInt2
,
tmpInt3
;
void
BlePoll
::
smWaitAckComS
()
{
byte
tmpByte
;
short
tmpShort
;
bleState
=
2110
;
if
(
timeOut
())
{
// Wenn der Slave nicht antwortet (kann auch eine Störung sein),
// dann wird seine Priorität heruntergesetzt (Zählwert erhöht)
// und der nächste Slave aus der Poll-Liste angefragt
// byte oldPduCount;
curSlave
->
prioSet
++
;
if
(
curSlave
->
prioSet
>
curSlave
->
minPrio
)
curSlave
->
prioSet
=
curSlave
->
minPrio
;
curPoll
->
prioCnt
=
curSlave
->
prioSet
;
curSlave
->
cntTo
++
;
pollIdx
++
;
if
(
pollIdx
>
pollMaxNr
)
pollIdx
=
1
;
radio
->
disable
(
txmPoll
);
next
(
smReqComS
);
return
;
}
if
(
radio
->
fin
(
txmPoll
,
&
crcError
))
{
cntAllRecs
++
;
// Wenn (irgend-) ein Beacon eingegangen ist,
// wird die maximale (BLE-Standard) Anzahl von Bytes kopiert
//
radio
->
getRecData
(
&
pduIn
,
39
);
if
(
pduIn
.
adr3
!=
pduOut
.
adr3
||
pduIn
.
adr4
!=
pduOut
.
adr4
||
pduIn
.
adr5
!=
pduOut
.
adr5
)
{
// Beacons aus fremdem Netzen werden nur gezählt und es wird weiter gewartet
//
cntAlien
++
;
pollIdx
++
;
if
(
pollIdx
>
pollMaxNr
)
pollIdx
=
1
;
next
(
smReqComS
);
return
;
}
if
(
pduIn
.
adr0
!=
pduOut
.
adr0
||
(
pduIn
.
adr1
&
0x3F
)
!=
(
pduOut
.
adr1
&
0x3F
))
{
// Beacons mit falscher Slaveadresse werden ebenfalls nur gezählt
// Hier wird später die Rundrufübertragung implementiert
//
cntWrong
++
;
pollIdx
++
;
if
(
pollIdx
>
pollMaxNr
)
pollIdx
=
1
;
next
(
smReqComS
);
return
;
}
// Antwort vom richtigen Teilnehmer ist eingegangen
//
if
(
crcError
)
{
// Die Daten werden bei einem CRC-Fehler verworfen.
// Der Fehler wird gezählt und ist ein Hinweis auf fremde
// Funkaktivitäten
//
curSlave
->
cntErrCrc
++
;
pollIdx
++
;
if
(
pollIdx
>
pollMaxNr
)
pollIdx
=
1
;
next
(
smReqComS
);
return
;
}
// Die Daten werden in der Slave-Struktur abgelegt
//
curSlave
->
result
.
counter
=
pduIn
.
data
[
0
];
curSlave
->
result
.
type
=
pduIn
.
data
[
1
];
curSlave
->
result
.
appId
=
pduIn
.
data
[
2
];
curSlave
->
result
.
measCnt
=
pduIn
.
data
[
3
];
curSlave
->
result
.
meas
[
0
]
=
*
(
word
*
)
&
pduIn
.
data
[
4
];
curSlave
->
result
.
meas
[
1
]
=
*
(
word
*
)
&
pduIn
.
data
[
6
];
curSlave
->
result
.
meas
[
2
]
=
*
(
word
*
)
&
pduIn
.
data
[
8
];
curSlave
->
result
.
meas
[
3
]
=
*
(
word
*
)
&
pduIn
.
data
[
10
];
curSlave
->
result
.
meas
[
4
]
=
*
(
word
*
)
&
pduIn
.
data
[
12
];
curSlave
->
result
.
meas
[
5
]
=
*
(
word
*
)
&
pduIn
.
data
[
14
];
if
(
curSlave
->
delayCnt
==
0
)
{
tmpByte
=
curSlave
->
result
.
counter
-
curSlave
->
oldPduCount
;
if
(
tmpByte
>
1
)
curSlave
->
cntLostPdu
+=
tmpByte
-
1
;
tmpByte
=
curSlave
->
result
.
measCnt
-
curSlave
->
oldMeasCount
;
if
(
tmpByte
>
1
)
curSlave
->
cntLostMeas
+=
tmpByte
-
1
;
}
else
curSlave
->
delayCnt
--
;
curSlave
->
oldPduCount
=
curSlave
->
result
.
counter
;
curSlave
->
oldMeasCount
=
curSlave
->
result
.
measCnt
;
curSlave
->
newPdu
=
true
;
curSlave
->
cntAckDP
++
;
curPoll
->
prioCnt
=
curSlave
->
prioSet
;
pollIdx
++
;
if
(
pollIdx
>
pollMaxNr
)
pollIdx
=
1
;
next
(
smReqComS
);
return
;
}
}
void
BlePoll
::
smEndComS
()
{
if
(
pollStop
||
pollStopped
)
{
pollStopped
=
true
;
return
;
}
// Von vorne (zur Zeit, Test)
//
adr
=
1
;
slaveIdx
=
adr
;
next
(
smReqEadr
);
}
// ----------------------------------------------------------------------------
// Datenübertragung Master M a s t e r - > S l a v e
// ----------------------------------------------------------------------------
//
void
BlePoll
::
smReqComE
()
{
bleState
=
4100
;
if
(
!
radio
->
disabled
(
txmRead
))
{
radio
->
disable
(
txmRead
);
return
;
}
curSlave
=
&
slaveList
[
slaveIdx
];
curSlave
->
adr
=
adr
;
curSlave
->
area
=
area
;
curSlave
->
chn
=
chn
;
setPduAddress
();
//setTimeOut(2000);
// Test
setTimeOut
(
1000000
);
radio
->
send
(
&
pduOut
,
txmRead
);
radio
->
getStatistics
(
&
statistic
);
cntPolling
++
;
next
(
smWaitNak
);
}
void
BlePoll
::
smWaitAckComE
()
{
bleState
=
4110
;
if
(
timeOut
())
{
radio
->
disable
(
txmRead
);
curSlave
->
cntTo
++
;
adr
++
;
slaveIdx
=
adr
;
if
(
adr
>
maxAdr
)
next
(
smEndEP
);
else
next
(
smReqEadr
);
return
;
}
if
(
radio
->
fin
(
txmRead
,
&
crcError
))
{
radio
->
getRecData
(
&
pduIn
,
8
);
if
(
pduIn
.
adr3
!=
pduOut
.
adr3
||
pduIn
.
adr4
!=
pduOut
.
adr4
||
pduIn
.
adr5
!=
pduOut
.
adr5
)
{
cntAlien
++
;
radio
->
cont
(
txmRead
);
return
;
}
if
(
pduIn
.
adr0
!=
pduOut
.
adr0
||
(
pduIn
.
adr1
&
0x3F
)
!=
(
pduOut
.
adr1
&
0x3F
))
{
cntWrong
++
;
radio
->
cont
(
txmRead
);
return
;
}
radio
->
disable
(
txmRead
);
curSlave
->
cntNakEP
++
;
cntAllNaks
++
;
adr
++
;
slaveIdx
=
adr
;
if
(
adr
>
maxAdr
)
next
(
smEndEP
);
else
next
(
smReqEadr
);
}
radio
->
getStatistics
(
&
statistic
);
}
void
BlePoll
::
smEndComE
()
{
if
(
pollStop
||
pollStopped
)
{
pollStopped
=
true
;
return
;
}
// Von vorne (zur Zeit, Test)
//
adr
=
1
;
slaveIdx
=
adr
;
next
(
smReqEadr
);
}
// ----------------------------------------------------------------------------
// Datenübertragung Slave M a s t e r < - > S l a v e
// ----------------------------------------------------------------------------
//
dword
smStartComESCnt
;
void
BlePoll
::
smStartComES
()
{
bool
newValues
;
byte
lenValues
;
bleState
=
1310
;
smStartComESCnt
++
;
if
(
cbData
==
NULL
)
{
next
(
smIdle
);
return
;
}
if
(
!
radio
->
disabled
(
txmResp
))
{
radio
->
disable
(
txmResp
);
cntWaitDisabled
++
;
return
;
}
nak
=
true
;
eadr
=
true
;
setPduAddress
(
&
pduIn
);
pduIn
.
len
=
6
;
nak
=
false
;
eadr
=
false
;
setPduAddress
(
&
pduOut
);
newValues
=
getValues
(
&
pduOut
);
radio
->
setChannel
(
chn
);
radio
->
send
(
&
pduIn
,
&
pduOut
,
txmResp
,
newValues
);
setTimeOut
(
wdTimeOut
);
next
(
smWaitComES
);
}
void
BlePoll
::
smWaitComES
()
{
bleState
=
1320
;
radio
->
getStatistics
(
&
statistic
);
if
(
timeOut
())
{
next
(
smStartComES
);
return
;
}
if
(
!
radio
->
fin
(
txmResp
,
&
crcError
))
return
;
next
(
smStartComES
);
}
// --------------------------------------------------------------------------
// Debugging
// --------------------------------------------------------------------------
//
dword
BlePoll
::
debGetDword
(
int
idx
)
{
dword
retv
=
0
;
switch
(
idx
)
{
case
0
:
retv
=
plMode
;
break
;
case
1
:
retv
=
cntAllRecs
;
break
;
case
2
:
retv
=
cntAllNaks
;
break
;
case
3
:
retv
=
cntAllTo
;
break
;
case
4
:
retv
=
cntAlien
;
break
;
case
5
:
retv
=
cntWrong
;
break
;
case
6
:
retv
=
statistic
.
pollAcks
;
break
;
case
7
:
retv
=
statistic
.
pollNaks
;
break
;
case
8
:
retv
=
bleState
;
break
;
case
9
:
retv
=
radio
->
getState
();
break
;
}
return
(
retv
);
}
dword
BlePoll
::
getStatistics
(
TxStatisticsPtr
dest
)
{
*
dest
=
statistic
;
return
(
bleState
);
}
SlavePtr
BlePoll
::
getSlavePtr
(
int
idx
)
{
return
(
&
slaveList
[
idx
]);
}
PollStatePtr
BlePoll
::
getPollPtr
(
int
idx
)
{
return
(
&
pollList
[
idx
]);
}
This diff is collapsed.
Click to expand it.
libraries/BlePoll/BlePoll.h
0 → 100644
+
372
−
0
View file @
3a4e0c04
//-----------------------------------------------------------------------------
// Thema: Social Manufacturing Network / Development Environment
// Datei: BlePoll.h
// Editor: Robert Patzke
// URI/URL: www.mfp-portal.de
//-----------------------------------------------------------------------------
// Lizenz: CC-BY-SA (wikipedia: Creative Commons)
// Datum: 1. September 2021
//
// Diese Bibliothek (Klassse) enthält diverse Ressourcen zur Kommunikation
// über BLE-Funkmodule auf niedriger Ebene, also dem direkten Telegrammaustausch.
// Darauf aufbauend sollen mehrkanalige Messeinrichtungen mit möglichst
// geringen Latenzzeiten entwickelt werden.
//
#ifndef BlePoll_h
#define BlePoll_h
// ----------------------------------------------------------------------------
#include
"stddef.h"
#include
"string.h"
#include
"arduinoDefs.h"
#include
"bleSpec.h"
#include
"IntrfRadio.h"
#define MAXSLAVE 100
// Betriebsmodus (Polling und Slave)
//
typedef
enum
_PlMode
{
plmIdle
,
// Ruhezustand, Gerät nicht im Netz aktiv
plmTest
,
// Low Level Tests
plmEmpty
,
// Leeres Polling (Aufbau Adressliste)
plmScan
,
// Daten aller aktiven Teilnehmer holen (Master)
plmSoaapM
,
// Vollständiger Betrieb SOAAP (Master)
plmSoaapS
,
// Vollständiger Betrieb SOAAP (Slave)
plmXchg
// Daten übertragen (Slave, beide Richtungen)
}
PlMode
;
// Grundsätzliche Datenstruktur für die Nutzdaten
//
typedef
struct
_PlPduBase
{
byte
counter
;
// zyklischer Telegrammmzähler
byte
type
;
// Kennzeichnung der Datenstruktur (AppType)
byte
plData
[
29
];
// weitere spezifische Nutzdaten
}
PlPduBase
,
*
PlPduBasePtr
;
// Erweiterte Datenstruktur für die Nutzdaten
//
typedef
struct
_PlPduExtd
{
byte
counter
;
// zyklischer Telegrammmzähler
byte
type
;
// Kennzeichnung der Datenstruktur (AppType)
byte
plData
[
247
];
// weitere spezifische Nutzdaten
}
PlPduExtd
,
*
PlPduExtdPtr
;
// Datentypen (type in plPduBase)
//
typedef
enum
_PlpType
{
plptEmpty
,
// Leeres Telegramm (nur adresse)
plptBasic
,
// Grundlegende Bytestruktur
plptFullMeas
,
// Maximale Belegung mit 16-Bit Messwerten (word)
plptMeas3
,
// 3 Messwerte (1 Raumsensor)
plptMeas6
,
// 6 Messwerte (2 Raumsensoren)
plptMeas9
// 9 Messwerte (3 Raumsensoren)
}
PlpType
,
*
PlpTypePtr
;
// Spezifische Datenstrukturen
//
typedef
struct
_PlpFullMeas
{
byte
counter
;
// zyklischer Telegrammmzähler
byte
type
;
// Kennzeichnung der Datenstruktur (AppType)
word
meas
[
12
];
// Liste von 12 Messwerten
byte
appId
;
// Kennzeichnung für Dateninhalte (PlpType)
byte
align
;
// Wird nicht gesendet, kennzeichnet Alignement
}
PlpFullMeas
,
*
PlpFullMeasPtr
;
typedef
struct
_PlpMeas3
{
byte
counter
;
// zyklischer Telegrammmzähler
byte
type
;
// Kennzeichnung der Datenstruktur (AppType)
byte
appId
;
// Kennzeichnung für Dateninhalte (PlpType)
byte
measCnt
;
// Zähler für Messwertaktualisierung
word
meas
[
3
];
// Liste von 3 Messwerten
}
PlpMeas3
,
*
PlpMeas3Ptr
;
typedef
struct
_PlpMeas6
{
byte
counter
;
// zyklischer Telegrammmzähler
byte
type
;
// Kennzeichnung der Datenstruktur (AppType)
byte
appId
;
// Kennzeichnung für Dateninhalte (PlpType)
byte
measCnt
;
// Zähler für Messwertaktualisierung
word
meas
[
6
];
// Liste von 6 Messwerten
}
PlpMeas6
,
*
PlpMeas6Ptr
;
typedef
struct
_PlpMeas9
{
byte
counter
;
// zyklischer Telegrammmzähler
byte
type
;
// Kennzeichnung der Datenstruktur (AppType)
byte
appId
;
// Kennzeichnung für Dateninhalte (PlpType)
byte
measCnt
;
// Zähler für Messwertaktualisierung
word
meas
[
9
];
// Liste von 9 Messwerten
}
PlpMeas9
,
*
PlpMeas9Ptr
;
// Identifikator für die Art der Daten
//
typedef
enum
_MeasId
{
app
// Gestaltung/Bedeutung der Daten aus Anwendung
}
MeasId
,
*
MeasIdPtr
;
typedef
struct
_Slave
{
dword
timeOut
;
dword
cntTo
;
dword
cntErrCrc
;
dword
cntNakEP
;
dword
cntAckDP
;
dword
cntLostPdu
;
dword
cntLostMeas
;
dword
delayCnt
;
byte
adr
;
byte
area
;
byte
chn
;
byte
pIdx
;
word
prioSet
;
word
minPrio
;
PlpMeas6
result
;
bool
newPdu
;
byte
oldPduCount
;
byte
oldMeasCount
;
}
Slave
,
*
SlavePtr
;
typedef
struct
_PollInfo
{
dword
aliens
;
// Anzahl der netzfremden Aktivitäten
dword
wrongs
;
// Anzahl ungewünschter Netzaktivitäten
}
PollInfo
,
*
PollInfoPtr
;
typedef
struct
_PollState
{
byte
slIdx
;
// Index in der Slave-Liste
byte
status
;
// Zustand
word
prioCnt
;
// Prioritätszähler
}
PollState
,
*
PollStatePtr
;
typedef
bool
(
*
cbDataPtr
)(
PlpType
dataType
,
byte
*
dest
);
#define psSlaveWasPresent 0x01
#define psSlaveIsPresent 0x02
// ----------------------------------------------------------------------------
// B l e P o l l
// ----------------------------------------------------------------------------
class
BlePoll
{
public:
// -------------------------------------------------------------------------
// Öffentliche Datentypen
// -------------------------------------------------------------------------
//
typedef
enum
_ComType
{
ctMASTER
,
ctSLAVE
,
ctHybrid
}
ComType
;
// Identifikator für die Anwendung
//
typedef
enum
_AppType
{
atDefault
,
// Standard-Default-Anwendung
atTestSend
,
// einfacher Sendetest (Soaap)
atSOAAP
,
// Steuerung optischer und akustischer Ausgaben für Performance-Künstler
atDHA
// Dezentrale Hausautomatisierung
}
AppType
;
private
:
// -------------------------------------------------------------------------
// Private Datentypen
// -------------------------------------------------------------------------
//
typedef
void
(
BlePoll
::*
cbVector
)(
void
);
typedef
dword
(
*
MicsecFuPtr
)(
void
);
// --------------------------------------------------------------------------
// Lokale Daten
// --------------------------------------------------------------------------
//
IntrfRadio
*
radio
;
bcPdu
pduOut
;
bcPdu
pduIn
;
cbVector
nextState
;
MicsecFuPtr
micSec
;
cbDataPtr
cbData
;
dword
toSet
;
dword
toValue
;
dword
cycleMics
;
dword
cycleCnt
;
dword
wdTimeOut
;
int
chn
;
int
adr
;
int
area
;
bool
master
;
bool
eadr
;
bool
nak
;
bool
crcError
;
PlMode
plMode
;
PlMode
oldPlMode
;
PlpType
plpType
;
Slave
slaveList
[
MAXSLAVE
+
1
];
SlavePtr
curSlave
;
int
slaveIdx
;
// ist z.Zt. identisch mit Slaveadresse adr
PollState
pollList
[
MAXSLAVE
+
1
];
PollStatePtr
curPoll
;
int
pollIdx
;
int
pollNr
;
int
pollMaxNr
;
int
maxAdr
;
dword
cntPolling
;
dword
cntAllRecs
;
dword
cntAllTo
;
bool
pollStop
;
bool
pollStopped
;
dword
cntAllNaks
;
dword
cntAlien
;
dword
cntWrong
;
dword
cntWaitDisabled
;
dword
bleState
;
dword
runCounter
;
TxStatistics
statistic
;
PlpMeas6
valuePdu
;
bool
newValue
;
// Einstellungen für den Anwendungsbetrieb
//
bool
fullCycle
;
// Vollständige Anwendung (EP & Data)
int
epCycleTotal
;
// Anzahl der leeren Pollings gesamt
int
epCycleRun
;
// Anzahl der leeren Pollings nach Kontakt
dword
epTimeOut
;
// Time-Out in Mikrosekunden
// --------------------------------------------------------------------------
// Lokale Funktionen
// --------------------------------------------------------------------------
//
void
setPduAddress
();
void
setPduAddress
(
bcPduPtr
pduPtr
);
void
setTimeOut
(
dword
value
);
bool
timeOut
();
bool
getValues
(
bcPduPtr
pduPtr
);
// Zustandsmaschine
// -----------------------------
void
smInit
();
void
smIdle
();
// Leeres Polling Master
//
void
smStartEP
();
void
smReqEadr
();
void
smWaitNak
();
void
smEndEP
();
// Leeres Polling Slave
//
void
smWaitEadr
();
void
smEvalPoll
();
// Datenübertragung
//
void
smStartCom
();
// Master: Master -> Slave
//
void
smReqComE
();
void
smWaitAckComE
();
void
smEndComE
();
// Master: Slave -> Master
//
void
smReqComS
();
void
smWaitAckComS
();
void
smEndComS
();
// Slave: Master <-> Slave
//
void
smStartComES
();
void
smWaitComES
();
void
smEvalComES
();
// Test
//
void
smStartTest
();
void
smWaitTest
();
void
smLoopTest
();
public
:
// --------------------------------------------------------------------------
// Initialisierungen
// --------------------------------------------------------------------------
BlePoll
(
IntrfRadio
*
refRadio
,
dword
inCycleMics
);
BlePoll
(
IntrfRadio
*
refRadio
,
MicsecFuPtr
inMicroFu
);
void
init
(
IntrfRadio
*
refRadio
,
dword
inCycleMics
,
MicsecFuPtr
inMicroFu
);
void
begin
(
ComType
typeIn
,
int
adrIn
,
AppType
appType
,
dword
watchDog
);
void
setCbDataPtr
(
cbDataPtr
cbPtr
);
// --------------------------------------------------------------------------
// Konfiguration
// --------------------------------------------------------------------------
//
void
setPollAddress
(
int
chnIn
,
int
adrIn
,
int
areaIn
,
bool
masterIn
,
bool
eadrIn
,
bool
nakIn
);
void
setEmptyPollParams
(
int
cycleTotal
,
int
cycleRun
,
dword
timeOut
);
void
setDataPollParams
(
int
slAdr
,
int
prio
,
int
minPrio
,
dword
timeOut
);
// --------------------------------------------------------------------------
// Steuerung des Telegrammaustausches (Polling)
// --------------------------------------------------------------------------
//
void
run
();
// Test
//
// Leeres Polling
//
void
stopEP
();
void
resumeEP
();
bool
stoppedEP
();
// Laufender Betrieb
//
void
start
(
PlMode
inPlMode
);
// --------------------------------------------------------------------------
// Zugriff auf Polling-Informationen
// --------------------------------------------------------------------------
//
int
getSlaveList
(
byte
*
dest
,
int
maxByte
);
void
resetPollCounters
();
// --------------------------------------------------------------------------
// Debugging
// --------------------------------------------------------------------------
//
dword
debGetDword
(
int
idx
);
dword
getStatistics
(
TxStatisticsPtr
dest
);
SlavePtr
getSlavePtr
(
int
idx
);
PollStatePtr
getPollPtr
(
int
idx
);
};
// ----------------------------------------------------------------------------
#endif // BlePoll_h
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment