smalltalk
/
osmo-st-gsm
Archived
1
0
Fork 0

bearer: Create a generic GSMBitField helper, implement BearerCaps parsing

The single bearer cap octets are represented as classes and provide
getter/setter to the underlying byte. The BearerCapFrom.. provides a way
to parse and later generate the caps. Parse one example cap and dissect
it.
This commit is contained in:
Holger Hans Peter Freyther 2011-11-23 17:18:28 +01:00
parent c115abccca
commit 0cffe9f7ac
3 changed files with 305 additions and 16 deletions

262
GSM48.st
View File

@ -503,6 +503,247 @@ GSM48SimpleTag subclass: GSMPriorityLevel [
GSMPriorityLevel class >> elementId [ ^ 16r80 ]
]
Object subclass: GSMBitField [
| byte |
<category: 'OsmoGSM'>
<comment: 'I am a 7bit bitfield and provide nice access. I am
commonly used with the GSM fields where the 8th indicate if things
continue or not. I can automatically generate accessors based on
a bit definition class'>
GSMBitField class >> fromByte: aByte [
<category: 'creation'>
^ self new
byte: aByte;
yourself
]
GSMBitField class >> initialize [
<category: 'protected'>
self bitDefinition do: [:each |
self compile: '%1 [ ^ self bitsFrom: (%2 to: %3) ]'
% {each first. each second. each third};
compile: '%1: aVal [ self atBits: (%2 to: %3) put: aVal]'
% {each first. each second. each third}.
]
]
data [
<category: 'access'>
^ byte
]
byte: aByte [
<category: 'private'>
byte := aByte
]
bitsFrom: interval [
| res mask |
<category: 'private'>
"Build the mask"
mask := 0.
interval do: [:each |
mask := mask bitAt: each put: 1].
"And with the value and shift"
res := (byte bitAnd: mask) bitShift: (interval first - 1) negated.
^ res
]
atBits: interval put: aVal [
| shifted |
aVal highBit > interval last ifTrue: [
^ self error: 'Value bigger than interval'.
].
shifted := aVal bitShift: interval first - 1.
interval do: [:each |
byte := byte bitAt: each put: (shifted bitAt: each)].
]
]
GSMBitField subclass: GSMBearerCapOctet3 [
<category: 'OsmoGSM'>
<comment: '10.5.4.5 Octet3'>
GSMBearerCapOctet3 class [
radioChReqReserved [ ^ 2r00 ]
radioChReqFullRateOnly [ ^ 2r01 ]
radioChReqDualHalfPref [ ^ 2r10 ]
radioChReqDualFullPref [ ^ 2r11 ]
radioCodStdGSM [ ^ 2r0 ]
radioCodStdReserved [ ^ 2r1 ]
transferModeCircuit [ ^ 2r0 ]
transferModePacket [ ^ 2r1 ]
transferCapSpeech [ ^ 2r000 ]
transferCapUnrest [ ^ 2r001 ]
transferCap31khzPlmn [ ^ 2r010 ]
transferCapFacsimileGroup3 [ ^ 2r011 ]
transferCapOtherITC [ ^ 2r101 ] "see Octet 5a"
transferCapReserved [ ^ 2r111 ]
bitDefinition [
"Bit definition of Octet3"
^ OrderedCollection new
add: #('informationTransferCapability' 1 3);
add: #('transferMode' 4 4);
add: #('codingStandard' 5 5);
add: #('radioChannelRequirement' 6 7);
yourself
]
]
]
GSMBitField subclass: GSMBearerCapOctet3a [
<category: 'OsmoGSM'>
<comment: '10.5.4.5 Octet3a MS to network'>
GSMBearerCapOctet3a class [
codingForTransferCapability [ ^ 2r0 ]
codingForOtherExtensions [ ^ 2r1 ]
ctmTextTelephonyNotSupported [ ^ 2r0 ]
ctmTextTelephonySupported [ ^ 2r1 ]
speechFullRateVersion1 [ ^ 2r0000 ]
speechFullRateVersion2 [ ^ 2r0010 ]
speechFullRateVersion3 [ ^ 2r0100 ]
speechHalfRateVersion1 [ ^ 2r0001 ]
speechHalfRateVersion3 [ ^ 2r0101 ]
bitDefinition [
^ OrderedCollection new
add: #('speechVersionIndication' 1 4);
add: #('spare' 5 5);
add: #('ctm' 6 6);
add: #('coding' 7 7);
yourself
]
]
]
GSMBearerCapOctet3a subclass: GSMBearerCapOctet3b [
<category: 'OsmoGSM'>
<comment: '10.5.4.5 Octet3b network to MS'>
GSMBearerCapOctet3b class [
bitDefinition [
"There is no CTM in this directtion"
^ OrderedCollection new
add: #('speechVersionIndication' 1 4);
add: #('spare' 5 6);
add: #('coding' 7 7);
yourself
]
]
]
Object subclass: GSMBearerCapDecoderBase [
| octet3 |
<category: 'OsmoGSM'>
<comment: 'I am the base of BearerCapDecoder parsing. My children
can parse the 10.5.4.5 bearer caps.'>
GSMBearerCapDecoderBase class >> parse: aStream [
^ self new
parse: aStream;
checkEndOfStream: aStream;
yourself
]
octet3 [
^ octet3
]
parse: aStream [
<category: 'protected'>
^ self parseOctet3: aStream
]
parseOctet3: aStream [
| byte |
"I return true if there is more for octet3"
<category: 'protected'>
octet3 := nil.
"nothing left to read"
aStream atEnd ifTrue: [
^ false].
octet3 := GSMBearerCapOctet3 fromByte: aStream next.
^ (octet3 data bitAt: 8) = 0.
]
parseOctets: aStream do: aBlock [
<category: 'protected'>
[aStream atEnd] whileFalse: [
| byte |
byte := aStream next.
aBlock value: byte.
"Check if we are at an end here"
(byte bitAt: 8) = 1 ifTrue: [
^ self
]
]
]
checkEndOfStream: aStream [
<category: 'private'>
aStream atEnd ifFalse: [
^ self error: 'Bearercaps not fully consumed.'
].
]
]
GSMBearerCapDecoderBase subclass: GSMBearerCapFromNetwork [
| octet3b |
<category: 'OsmoGSM'>
parse: aStream [
<category: 'private'>
octet3b := nil.
(self parseOctet3: aStream) ifTrue: [
self parseOctets: aStream do: [:each |
self octet3b add: (GSMBearerCapOctet3b fromByte: each)]
].
]
octet3b [
<category: 'accessing'>
^ octet3b ifNil: [octet3b := OrderedCollection new]
]
]
GSMBearerCapDecoderBase subclass: GSMBearerCapFromMS [
| octet3a |
<category: 'OsmoGSM'>
parse: aStream [
<category: 'private'>
octet3a := nil.
(self parseOctet3: aStream) ifTrue:[
self parseOctets: aStream do: [:each |
self octet3a add: (GSMBearerCapOctet3a fromByte: each)].
]
]
octet3a [
<category: 'accessing'>
^ octet3a ifNil: [octet3a := OrderedCollection new]
]
]
GSM48DataHolder subclass: GSMBearerCap [
<category: 'OsmoGSM'>
<comment: '10.5.4.5'>
@ -511,23 +752,7 @@ GSM48DataHolder subclass: GSMBearerCap [
GSMBearerCap class >> validSizes [ ^ 1 to: 13 ]
"GSM 04.08 Table 10.5.102. Strings depend on other attributes"
GSMBearerCap class >> radioChReqReserved [ ^ 2r00 ]
GSMBearerCap class >> radioChReqFullRateOnly [ ^ 2r01 ]
GSMBearerCap class >> radioChReqDualHalfPref [ ^ 2r10 ]
GSMBearerCap class >> radioChReqDualFullPref [ ^ 2r11 ]
GSMBearerCap class >> radioCodStdGSM [ ^ 2r0 ]
GSMBearerCap class >> radioCodStdReserved [ ^ 2r1 ]
GSMBearerCap class >> transferModeCircuit [ ^ 2r0 ]
GSMBearerCap class >> transferModePacket [ ^ 2r1 ]
GSMBearerCap class >> transferCapSpeech [ ^ 2r000 ]
GSMBearerCap class >> transferCapUnrest [ ^ 2r001 ]
GSMBearerCap class >> transferCap31khzPlmn [ ^ 2r010 ]
GSMBearerCap class >> transferCapFacsimileGroup3 [ ^ 2r011 ]
GSMBearerCap class >> transferCapOtherITC [ ^ 2r101 ] "see Octet 5a"
GSMBearerCap class >> transferCapReserved [ ^ 2r111 ]
]
GSM48DataHolder subclass: GSMFacility [
@ -1703,4 +1928,9 @@ Eval [
GSM48SSFacility initialize.
GSM48SSRegister initialize.
GSM48SSReleaseComplete initialize.
"single parts of the IEs"
GSMBearerCapOctet3 initialize.
GSMBearerCapOctet3a initialize.
GSMBearerCapOctet3b initialize.
]

View File

@ -293,6 +293,37 @@ TestCase subclass: GSM48Test [
dec := GSM48MSG decode: inp.
self assert: dec toMessage asByteArray = inp.
]
testGSMBearerParser [
| cap decoded |
cap := GSMBearerCap parseFrom: #(16r04 16r60 16r02 16r00 16r81).
decoded := GSMBearerCapFromMS parse: cap data readStream.
self deny: decoded octet3 isNil.
self assert: decoded octet3a size = 3.
self assert: decoded octet3 informationTransferCapability = GSMBearerCapOctet3 transferCapSpeech.
self assert: decoded octet3 transferMode = GSMBearerCapOctet3 transferModeCircuit.
self assert: decoded octet3 codingStandard = GSMBearerCapOctet3 radioCodStdGSM.
self assert: decoded octet3 radioChannelRequirement = GSMBearerCapOctet3 radioChReqDualFullPref.
self assert: decoded octet3a first speechVersionIndication = GSMBearerCapOctet3a speechFullRateVersion2.
self assert: decoded octet3a first spare = 0.
self assert: decoded octet3a first ctm = GSMBearerCapOctet3a ctmTextTelephonyNotSupported.
self assert: decoded octet3a first coding = GSMBearerCapOctet3a codingForTransferCapability.
self assert: decoded octet3a second speechVersionIndication = GSMBearerCapOctet3a speechFullRateVersion1.
self assert: decoded octet3a second spare = 0.
self assert: decoded octet3a second ctm = GSMBearerCapOctet3a ctmTextTelephonyNotSupported.
self assert: decoded octet3a second coding = GSMBearerCapOctet3a codingForTransferCapability.
self assert: decoded octet3a third speechVersionIndication = GSMBearerCapOctet3a speechHalfRateVersion1.
self assert: decoded octet3a third spare = 0.
self assert: decoded octet3a third ctm = GSMBearerCapOctet3a ctmTextTelephonyNotSupported.
self assert: decoded octet3a third coding = GSMBearerCapOctet3a codingForTransferCapability.
]
]
SCCPHandler subclass: TestSCCPHandler [
@ -671,3 +702,30 @@ TestCase subclass: GSMEncodingTest [
self assert: #(49 217 140 86 179 221 26 13) asByteArray decodeUSSD7Bit = wanted.
]
]
TestCase subclass: BitfieldTest [
<comment: 'I test the Bitfield class'>
testFromByte [
| res |
res := GSMBitField fromByte: 16r5A.
self assert: (res bitsFrom: (1 to: 1)) = 2r0.
self assert: (res bitsFrom: (2 to: 2)) = 2r1.
self assert: (res bitsFrom: (1 to: 2)) = 2r10.
self assert: (res bitsFrom: (3 to: 4)) = 2r10.
self assert: (res bitsFrom: (5 to: 8)) = 2r0101.
self assert: (res bitsFrom: (5 to: 5)) = 2r1.
]
testByteSet [
| res |
res := GSMBitField fromByte: 16rFF.
res atBits: (1 to: 2) put: 2r10.
res atBits: (3 to: 4) put: 2r10.
res atBits: (5 to: 8) put: 2r0101.
self assert: res data = 16r5A.
]
]

View File

@ -20,6 +20,7 @@
<sunit>OsmoGSM.TestMessages</sunit>
<sunit>OsmoGSM.SCCPHandlerTest</sunit>
<sunit>OsmoGSM.GSMEncodingTest</sunit>
<sunit>OsmoGSM.BitfieldTest</sunit>
<filein>Tests.st</filein>
</test>