Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ. (επεξεργασμένο)

Καλησπέρα.

Background:

Έχω μια GSM Voip gateway (Portech MV-372) και πρέπει να φτιάξω ένα php script που τραβάει τα SMS από την μνήμη της SIM.

Το κομμάτι με τις AT εντολές το έχω ετοιμάσει και είμαι σε θέση να τραβήξω όλα τα μηνύματα. Καθώς όμως υπάρχουν Ελληνικοί χαρακτήρες στο message, πρέπει να τραβήξω την πληροφορία σε PDU mode.

Χωρίζω σωστά την πληροφορία στα μέρη της. Αλλά όταν το sender type είναι D0 και όχι 91, η κωδικοποίηση του sender είναι 8bit Octets που πρέπει να μετατραπούν σε 7Bit ώστε να μπορώ να πάρω τους χαρακτήρες που αντιστοιχούν στο 7 bit default alphabet

Αυτό που έχω κάνει στο κομμάτι αυτό είναι το εξής:

 

>$sevenbitdefault = array(
'@', '£', '$', '¥', 'è', 'é', 'ù', 'ì', 'ò', 'Ç', '\n', 'Ø', 'ø', '\r', 'Å', 'å',
'\u0394', '_', '\u03a6', '\u0393', '\u039b', '\u03a9', '\u03a0', '\u03a8',
'\u03a3', '\u0398', '\u039e', esc, 'Æ', 'æ', 'ß', 'É',
' ', '!', '"', '#', '¤', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
'¡', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Ä', 'Ö', 'Ñ', 'Ü', '§',
'¿', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'ä', 'ö', 'ñ', 'ü', 'à'
);
$hex = array('C3','F7','BC','FD','A6','97','01');
$bin8 = array();

foreach($hex as $he){
   $bin8[]=str_pad(decbin(hexdec($he)),8,'0',STR_PAD_LEFT);
}
$takeBins = 1;
for ($i=0;$i<count($bin8);$i++){
   if ($i%6 == 0 && $i!=0)
       array_splice($bin8, $i+1, 0, '');//VALE META ENA KENO
   $move = substr($bin8[$i],0,$takeBins);
   if ($i!=(count($bin8)-1)){
   $bin8[$i+1]=$bin8[$i+1].$move;
   }
   $bin8[$i]=substr($bin8[$i],$takeBins,7);
   $takeBins++;
   if ($takeBins==8)
       $takeBins=0;
} 
for($i = 0; $i < count ( $bin8 ); $i ++) {
		$bin8 [$i] = $sevenbitdefault [bindec ( $bin8 [$i] )];
	}

var_dump($bin8);

 

Το παραπάνω εκτυπώνει

>array(8) {
 [0]=>
 string(1) "C"
 [1]=>
 string(1) "o"
 [2]=>
 string(1) "s"
 [3]=>
 string(1) "m"
 [4]=>
 string(1) "o"
 [5]=>
 string(1) "t"
 [6]=>
 string(1) "e"
 [7]=>
 string(1) "@"
}

Ενώ θα έπρεπε να εκτυπώνει Cosmote χωρίς το @

Τον κώδικα τον δούλεψα πάνω στο παράδειγμα http://www.dreamfabric.com/sms/hello.html όπου και δουλεύει σωστά.

 

Μπορεί κανείς να δώσει μια βοήθεια;

 

ΥΓ. Το PDU πάνω στο οποίο δουλεύω είναι το εξής:

>06910379010005040DD0C3F7BCFDA6970141001101129142242144456C915A04C540CEE213D4443AB3CDA00BB40C528A186A111493CD402724683583D972B7180C068BC966A0493208720641D42728B87C6631456AD105

ΥΓ2. Ο PDU decoder http://smstools3.kekekasvi.com/topic.php?id=288 το εμφανίζει κανονικά, προσπάθησα να μετατρέψω τον javascript κώδικα του σε PHP αλλά ήταν μια αποτυχία και μισή...

Επεξ/σία από iLLiCiT
Δημοσ. (επεξεργασμένο)

Φίλε μου δεν είναι τόσο εύκολο να καταλάβει κανείς για τι πράγμα μιλάς, πόσο μάλλον τι προσπαθείς να κάνεις και ακόμα περισσότερο γιατί αυτό που κάνεις δεν δουλεύει σωστά -- θα έπρεπε να γίνεις λίγο πιο forthcoming με τις πληροφορίες. Anyway, το πνεύμα των Χριστουγέννων και η σελίδα-παράδειγμα του dreamfabric βοήθησαν για να βρεις απάντηση.

 

Ξεκινάω λέγοντας πως ο κώδικας που έχεις μοιάζει σα να βγήκε από διαγωνισμό "μπερδέψτε τον προγραμματιστή", οπότε παραιτήθηκα από την προσπάθεια να καταλάβω πού ακριβώς είναι το λογικό λάθος και με βάση το παράδειγμα τον ξανάγραψα από την αρχή. Δίνω σχόλια, αλλά η γενική ιδέα είναι ότι έχεις ένα προσωρινό buffer από bits (εσύ τα έκανες χαρακτήρες 0 και 1 αλλά είναι περιττό και πιο δυσκοίλιο). Κάθε φορά που θέλεις να βγάλεις ένα octet εξόδου, τραβάς τα 8 τελευταία bits από τον buffer και κάθε φορά που δεν υπάρχουν 8 να τραβήξεις, τραβάς ένα septet από την είσοδο και το προσθέτεις στην αρχή του buffer. Φαντάσου το σαν ένα κυλιόμενο ιμάντα που από τη μία μεριά μπαίνουν bits 7 κάθε φορά και από την άλλη βγαίνουν 8 κάθε φορά. Αν δεν έχεις να βγάλεις 8, περιμένεις μέχρι να μαζευτούν.

 

>function encode($input) {
   $input = str_split($input); // πίνακας για να τραβάω ένα-ένα septet με ευκολία
   $bitcount = $bitbucket = 0; // bitbucket = buffer από τον οποίο τραβάμε 8 bits κάθε φορά
   $result = array();          // bitcount = πόσα bits έχει μέσα ο bitbucket

   // Οι συνθήκες των while είναι λίγο "περίεργες". Εκ πρώτης όψεως θα έπρεπε να λείπει και από
   // τις 2 το δεύτερο μέρος, αλλά τότε θα έπρεπε να έχουμε ένα if στο τέλος (πριν το return)
   // που να λέει "αν το bitbucket έχει ακόμα μέσα πράμα, κάνε άλλη μια επανάληψη με ό,τι έχει μέσα
   // και τέλος". Επειδή αυτό σημαίνει ότι θα έπρεπε να ξαναγράψω τη γραμμή που προσθέτει στο
   // result άλλη μια φορά και επειδή το copy/paste στον προγραμματισμό είναι κακό πράγμα, αντί
   // για αυτό έγραψα τις συνθήκες έτσι που να κάνει αυτό που περιγράφω παραπάνω χωρίς ξεχωριστό
   // if στο τέλος.
   while(!empty($input) || $bitcount > 0) {
       while ($bitcount < 8 && !empty($input)) {
           // Aν ο bucket δεν έχει αρκετά bits, τράβα septets και κάντα prepend στον buffer
           // μέχρι να έχουμε μαζέψει τουλάχιστον 8 ή να τελειώσει η είσοδος.
           // Εδώ εσύ αντί για ord θα κάνεις search μέσα στον πίνακά σου, δηλαδή:
           // $bitbucket |= array_search(array_shift($input), $sevenbitdefault) << $bitcount;
           $bitbucket |= ord(array_shift($input)) << $bitcount;
           $bitcount += 7;
       }

       // τώρα ο buffer έχει τουλάχιστον 8 bits, οπότε τράβα ένα octet
       // και σβήσε τα 8 που χρησιμοποίησες
       $result[] = dechex($bitbucket & 0xff);
       $bitbucket >>= 8;
       $bitcount -= 8;
   }

   // voila!
   return $result;
}

 

Τώρα, για την ανάποδη δουλειά κάνεις σχεδόν το ίδιο πράγμα με ελάχιστες διαφορές, π.χ. η είσοδος είναι πίνακας hex-encoded αριθμών αντί για string, δεν χρειάζεσαι δεύτερο while γιατί τραβάς κάθε φορά 7 bits (επομένως δεν υπάρχει περίπτωση να χρειαστεί πάνω από ένα "γέμισμα" των 8 bits για να μαζευτούν 7), κάποιες σταθερές αλλάζουν από 7 σε 8 και το αντίστροφο.

 

>function decode(array $input) {
   $input = array_map('hexdec', $input);
   $bitcount = $bitbucket = 0;
   $result = '';

   while(!empty($input) || $bitcount > 0) {
       if ($bitcount < 7 && !empty($input)) {
           $bitbucket |= array_shift($input) << $bitcount;
           $bitcount += 8;
       }

       // Για να δουλέψουν τα ελληνικά, εδώ αντί για chr εσύ θα κάνεις index μέσα στον πίνακά σου,
       // $result .= $sevenbitdefault[$bitbucket & 0x7f]
       $result .= chr($bitbucket & 0x7f);
       $bitbucket >>= 7;
       $bitcount -= 7;
   }

   return $result;
}

 

Δες το να τρέχει με το παράδειγμα του dreamfabric.

 

Edit:

 

Τρία σχολια:

 

1. Κάποιος δεν ενημέρωσε τον τύπο που έγραψε τη Javascript που δίνεις link παραπάνω πως γράφει JS και όχι C.

2. Οι 2 παραπάνω functions μοιάζουν ανησυχητικά πολύ δε νομίζετε;

3. Καταλαβαίνεις ότι έχεις γράψει καλό κώδικα όταν μπορείς να κάνεις αυτό:

 

>function transform(array $input, $inBitQuantum, $outBitQuantum) {
   $bitcount = $bitbucket = 0;
   $result = array();

   $outBitMask = ~(~0 << $outBitQuantum);

   while(!empty($input) || $bitcount > 0) {
       while ($bitcount < $outBitQuantum && !empty($input)) {
           $bitbucket |= array_shift($input) << $bitcount;
           $bitcount += $inBitQuantum;
       }

       $result[] = $bitbucket & $outBitMask;
       $bitbucket >>= $outBitQuantum;
       $bitcount -= $outBitQuantum;
   }

   return $result;
}


$encoded = array_map('dechex', transform(array_map('ord', str_split('hellohello')), 7, 8));
var_dump($encoded);
$decoded = implode('', array_map('chr', transform(array_map('hexdec', $encoded), 8, 7)));
var_dump($decoded);

 

Δες το να τρέχει.

Επεξ/σία από defacer
Δημοσ.

Το τι προσπαθώ να κάνω το περιέγραψα στην 2η κιόλας γραμμή του post. Ένα απλό decode PDU για να διαβάσω τα μηνύματα από την μνήμη της SIM.

 

Για να γράψεις καλό κώδικα πρέπει να καταλαβαίνεις πια η λογική, ποιος ο σκοπός και πιο το αποτέλεσμα μιας διαδικασίας και για εμένα η όλη μετατροπή του 8Bit σε 7Bit έμοιαζε απλά ανούσια και "εξωγήινη". Γι' αυτό και ο σκοπός μου από την στιγμή που δεν καταλάβαινα τι έκανα και γιατί το έκανα, παρά μόνο δούλευα πάνω στο παράδειγμα, ήταν να κάνω κάτι που να δουλεύει.

 

Αυτό που έδωσες κάνει καθαρά την δουλειά του. Thanks. Με γλύτωσες από 2 μέρες πονοκέφαλο.

 

Χρόνια πολλά και καλή χρονιά.

Δημοσ.

Αυτό ακριβώς εννοώ: δε νομίζω ότι οι περισσότεροι που θα το διάβαζαν ξέρουν ούτε καν τι είναι PDU, πόσο μάλλον τι πρέπει να κάνεις για να διαβάσεις από τη SIM (εγώ τουλάχιστον δεν ήξερα και μιας και δεν έκανα google "pdu sim" ακόμα δεν ξέρω).

 

Τα περι καλού κώδικα τα είπα μόνο σαν επειχείρημα ότι αυτή η υλοποίηση ήταν "η σωστή", όχι για να κατακρίνω ούτε για κάποιον άλλο λόγο. Ένα πράγμα σα να λέμε πως όταν το έχεις πιάσει από το σωστό μέρος, όλα τα κομμάτια του παζλ κάνουν κλικ.

 

Καλές γιορτές!

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...