Archive for October 24th, 2007
Javacard code to send SMS (Unformated SMS-PP & 7Bit TP-UD)
TP-UD of SMS as defined in GSM 03.40 can contain up to 140 octet/bytes. But some common people always ask, are you sure only 140 bytes? Because normally we can send 160 character. Yes, because those 160 character is actually a 7bit data (septet), means with 140 octet we can send 140 * 8/7 ~ 160 septet. I hope you know it now
Ok, some javacard programmer ask how to send SMS Unformatted PP (means not include GSM 03.48 header) with 7bit TP-UD? Let me show you.
1. You need to define these variables somewhere inside your javaclass
// Variable to declare inside your class private byte[] bSendSMSBuffer; // Buffer of TP-UD SMS private byte[] ramUnPacked; private byte[] ramPacked;
2. You need to allocate memory for this, normally you should put it on RAM rather on EEPROM, because do writing on EEPROM too oftenly will kill the card. Normally you will put these codes inside your javacard class constructor
try{
// Allocate buffer on RAM and free it once the applet is deselected
bSendSMSBuffer = JCSystem.makeTransientByteArray( ( short )160,
JCSystem.CLEAR_ON_DESELECT );
}catch (SystemException e){
// Allocate buffer on EEPROM, if your application will write a lot on this variable,
// this one should be avoided if possible
bSendSMSBuffer = new byte[(short)160];
}
try{
ramUnPacked = JCSystem.makeTransientByteArray( (short)8,
JCSystem.CLEAR_ON_DESELECT);
}catch(SystemException e){
ramUnPacked = new byte[(short)8];
}
try{
ramPacked = JCSystem.makeTransientByteArray( (short)8,
JCSystem.CLEAR_ON_DESELECT);
}catch(SystemException e){
ramPacked = new byte[(short)8];
}
3. Add this 2 function on your javacard class code:
// Send sms function
// input: tpud, len of tpud, destination address , len of destination address
public byte sendSMS(byte[] dataBuff, short Len,byte[] DesAdd, short DesLen) throws UserException {
ProactiveHandler proHdlr = ProactiveHandler.getTheHandler();
short smstpduLength = (short) 0;
short numberLength = (byte) 0;
final byte CMD_QUALIFIER_PACKING_NOT_REQUIRED = (byte) 0;
//Initialize the recordbuffer to Construct the Sms-TPDU Buffer
Util.arrayFillNonAtomic(bSendSMSBuffer, (short)0,
(short)bSendSMSBuffer.length, (byte)0x00);
// Now Construct the Sms TPDU in the recordData
// see GSM 03.40 for details
bSendSMSBuffer[smstpduLength++] = (byte) 0x01; //SMS-Submit Type
bSendSMSBuffer[smstpduLength++] = (byte) 0x01; //Message reference
// TP-Destination Address
Util.arrayCopy(DesAdd,(short)0, bSendSMSBuffer, smstpduLength,(short)DesLen);
smstpduLength = (short) ((short) smstpduLength + (short)DesLen);
bSendSMSBuffer[smstpduLength++] = (byte) 0x00; // TP-PID 0x00
bSendSMSBuffer[smstpduLength++] = (byte) 0x00; // TP-DCS 0x00
bSendSMSBuffer[smstpduLength++] = (byte) Len; // TP-UDL (User Data Length)
// Pack data to 7 bit before sending
convert_8bit_2_7bit( dataBuff, (short)0, Len, bSendSMSBuffer, smstpduLength );
short f = 0;
f = (short)((short)(Len * 7 )/(short)8 );
if((short)(Len % 8 ) != (short)0){
f++;
}
smstpduLength+=f;
// Sending the message
proHdlr.init(PRO_CMD_SEND_SHORT_MESSAGE,CMD_QUALIFIER_PACKING_NOT_REQUIRED, DEV_ID_NETWORK);
// Uncommented this one to add some text while sending sms
//proHdlr.appendTLV((byte) (TAG_ALPHA_IDENTIFIER),SENDING, (byte)0, (short) SENDING.length);
proHdlr.appendTLV((byte) (TAG_SMS_TPDU),bSendSMSBuffer, (byte)0, (short)smstpduLength);
return proHdlr.send();
}
private void convert_8bit_2_7bit( byte[] source,
short sourceStartOfst,
short sourceLen,
byte[] destin,
short destinOfst){
// Convert 8 bytes of data at each pass
short copyLength = (short) 8;
// Pointer pointing to the start offset
short sourcePtr = sourceStartOfst;
// Calculate the end offset of the unpacked data
short sourceEndOfst = (short) ( sourceStartOfst + sourceLen );
// Loop until gone through all the data
while ( sourcePtr < sourceEndOfst ){
// If the remaining data in Unpacked data is less than the 8 byte unit
if ( (short) ( sourcePtr + copyLength ) > sourceEndOfst ) {
// Get the remaining number of bytes
copyLength = (short) ( sourceEndOfst - sourcePtr );
// Clear the RAM data
Util.arrayFillNonAtomic( ramUnPacked, (short) 0, (short) 8, (byte) 0x00 );
}
// Copy from source data to RAM unpacked data
Util.arrayCopyNonAtomic( source, sourcePtr, ramUnPacked, (short) 0, copyLength );
// Update Source Pointer
sourcePtr += copyLength;
// Calculate 1st byte
ramPacked[0] = (byte) ( ( ( ramUnPacked[0] << 1 ) & 0xFE) | ( ( ramUnPacked[1] >> 6 ) & 0x01 ) );
// Calculate 2nd byte
ramPacked[1] = (byte) ( ( ( ramUnPacked[1] << 2 ) & 0xFC) | ( ( ramUnPacked[2] >> 5 ) & 0x03 ) );
// Calculate 3rd byte
ramPacked[2] = (byte) ( ( ( ramUnPacked[2] << 3 ) & 0xF8) | ( ( ramUnPacked[3] >> 4 ) & 0x07 ) );
// Calculate 4th byte
ramPacked[3] = (byte) ( ( ( ramUnPacked[3] << 4 ) & 0xF0) | ( ( ramUnPacked[4] >> 3 ) & 0x0F ) );
// Calculate 5th byte
ramPacked[4] = (byte) ( ( ( ramUnPacked[4] << 5 ) & 0xE0) | ( ( ramUnPacked[5] >> 2 ) & 0x1F ) );
// Calculate 6th byte
ramPacked[5] = (byte) ( ( ( ramUnPacked[5] << 6 ) & 0xC0) | ( ( ramUnPacked[6] >> 1 ) & 0x3F ) );
// Calculate 7th byte
ramPacked[6] = (byte) ( ( ( ramUnPacked[6] << 7 ) & 0x80) | ( ( ramUnPacked[7] >> 0 ) & 0x7F ) );
// Copy the RAM packed data to destination byte array
Util.arrayCopyNonAtomic( ramPacked, (short) 0, destin, destinOfst, (short) 7 );
// Update Destination Pointer
destinOfst += (short) 7;
}
}
And you then can simply sms like this:
1. For example you want to send SMS to 12345, you will need to create TP_DA (Destination Address) byte array containing:
1. first 1 byte that inform the length of address
2. 2nd 1 byte that inform TON/NPI
3. the rest is address in BCD swapped format
e.g like this:
private byte[] TPDA = {(byte)0x05,(byte)0x81,(byte)0x21,(byte)0x43,(byte)0xF5};
0x05 : Length of '12345' -> 5 bytes
0x81: TON/NPI
0x21 0x43 0xF5: BCD swapped format for address 12345
And then you define the SMS content like this:
private byte[] sms_content = {(byte)'T',(byte)'e',(byte)'s',(byte)'t')};
And then you send it like this
try{
sendSMS(sms_content,(short)sms_content.length, TPDA, (short)TPDA.length);
}catch(Exception e){
}
Good luck