 |
|
| Author |
Topic  |
|
|
pfys
New Member

Greece
105 Posts |
Posted - 25 July 2012 : 20:18:59
|
Σκέφτομαι να γράψω κάποια κείμενα για αντικειμενοστρεφή προγραμματισμό σε object pascal (Delphi). Δεν σκοπεύω να περιγράψω την γλώσσα αλλά να διατυπώσω κάποιους κανόνες και πρακτικές που έχω καταλήξει.
Μια πιθανή λίστα θεμάτων είναι η ακόλουθη. 1. Κλάση & αντικείμενα (Class vs Object). Πως και γιατί. 2. Object encapsulation, πολυμορφισμός, κληρονομικότητα. 3. Τυπική εφαρμογή, ενημέρωση της οθόνης και χρονοβόρες διαδικασίες. 4. TCP/IP sockets 5. Διεργασίες - Νήματα (Threads) σαν κομμάτι επεξεργασίας. 6. Πολυνηματικός TCP/IP Server 7. Modbus επικοινωνία μέσω TCP/IP 8. Σειριακή επικοινωνία. Διαγράμματα αλλαγής κατάστασης.
Υπάρχει ενδιαφέρον ?
|
|
|
stom
Senior Member
   
Greece
1665 Posts |
Posted - 26 July 2012 : 19:51:54
|
Πανε πολλα χρονια που εχω να δω Delphi και πιθανοτατα εχω χασει επεισοδια.
Παρολα αυτα, οι τεχνικες παραμενουν τεχνικες..
πχ modbus?
Burn baby, burn |
 |
|
|
dipoli
Administrator
    
Greece
4047 Posts |
Posted - 26 July 2012 : 20:09:27
|
Σιγουρα εγώ και πιθανότατα και ο Καπετάνιος θα ενδιαφέρεται.
Και γώ έχω να χρησιμοποιήσω τη γλώσσα απο το 1995 οπότε μιλάμε για πλήρη άγνοια....
I believe we should all pay our tax with a smile. I tried - but they wanted cash... |
 |
|
|
pfys
New Member

Greece
105 Posts |
Posted - 26 July 2012 : 21:15:36
|
Πάνω που είχα αρχίσει να απογοητεύομαι. Όλη η αναφορά σε TCP/IP και πολυνηματικούς servers είναι παραγγελιά από τον καπετάνιο. Από τα υπόλοιπα κάποια είναι κοινά για όλες τις OO γλώσσες και κάποια ειδικά σε Win32 με Delphi.
Υπάρχει μια μεγάλη αλλαγή στο πως γράφεις προγράμματα, σειριακά με C ή με Fortran και όταν χρησιμοποιείς objects. Αλλάζει ο τρόπος που σκέφτεσαι. Το ισοδύναμο που μπορώ να βρω είναι τα κλειστά κουτιά στα ΣΑΕ, με συγκεκριμένους εισόδους, λειτουργικότητα (συνάρτηση μεταφοράς) και εξόδους. Πολλά τέτοια κουτιά, συνδεδεμένα μεταξύ τους υλοποιούσαν το σύστημα.
|
 |
|
|
pfys
New Member

Greece
105 Posts |
Posted - 27 July 2012 : 00:17:08
|
1. Κλάση & αντικείμενα Aντικειμενοστρεφής προγραμματισμός είναι η διαδικασία σχεδίασης και υλοποίησης προγραμμάτων με βασική μονάδα την κλάση. Γνώρισε αποδοχή γιατί η M$oft, στα μέσα της δεκαετίας του 90, έβγαλε ένα πολύ καλό C++ compiler και προώθησε την C++ σαν γλώσσα για το COM, η Sun διέθεσε την Java σαν open source και η Borland προσπάθησε να λάμψει ξανά βγάζοντας στην αγορά σαν VB killer, το Delphi.
Η κλάση (class) είναι μία προδιαγραφή / ένα πρότυπο και δηλώνει την συμπεριφορά ή την λειτουργικότητα που μπορεί να παράσχει. Έχει ενσωματωμένα χαρακτηριστικά (μνήμη), ορατά ή όχι στους χρήστες της. Επιπλέον εκτελεί ενέργειες (μεθόδους), που χρησιμοποιούν την εσωτερική μνήμη και υλοποιούν την λειτουργικότητα της.
Έχει τέσσερα βασικά χαρακτηριστικά
Abstraction : επιτρέπει την δημιουργία αφαιρετικών μοντέλων Encapsulation: συνδέει δεδομένα και λειτουργίες. Κληρονομικότητα (Inheritance) : είναι η δυνατότητα μιας κλάσης να κληρονομήσει δεδομένα και μεθόδους μιας άλλης προγενέστερης κλάσης. Πολυμορφισμός (Polymorphism): η δυνατότητα μιας κλάσης να κληρονομήσει και να μεταβάλει τις συμπεριφορές μιας άλλης ανώτερης κλάσης.
Κάθε κλάση ορίζει μία μέθοδο δημιουργίας (constructor) μέσω της οποίας δημιουργούνται αντικείμενα. Το αντικείμενο υλοποιεί τις ιδιότητες του προτύπου (class).
Τα αντικείμενα αλληλεπιδρούν και ανταλλάσουν δεδομένα μεταξύ τους για να δημιουργήσουν τελικά ένα πρόγραμμα.
Στο Delphi τα objects δημιουργούνται πάντα δυναμικά και η αναφορά τους είναι ένας pointer. Ο compiler εξάλειψε την ανάγκη της χρήσης του ^ κατά την χρήση των objects.
Ορίζει επιπλέον και μία μέθοδο καταστροφής (destructor) του αντικειμένου που καλείται όταν παύει να χρησιμοποιείται και αποδεσμεύσει την μνήμη που χρησιμοποίησε..
Ας δούμε την κλάση ΤStream. http://delphi.about.com/od/vclusing/l/aa110803a.htm Το TStream είναι αφηρημένο και ανύπαρκτο. Οι κλάσεις TMemoryStream και TFileStream, που κληρονομούν τις ιδιότητες του, υλοποιούν την δυνατότητα να διαβάζουνε ή να γράφουνε σε μνήμη ή σε αρχείο αντίστοιχα.
Στο http://www.swissdelphicenter.ch/torry/showcode.php?id=822 δέστε την δήλωση της procedure CompressStream(inpStream, outStream: TStream); Διαβάζει δεδομένα από ένα stream στην μνήμη, τα συμπιέζει στην μνήμη και τα γράφει σε ένα άλλο stream.
Μια πρώτη προφανής βελτίωση είναι η απευθείας χρήση TFileStream που λειτουργεί απευθείας με αρχεία και δεν απαιτεί να διαβάζουμε πρώτα το περιεχόμενο στη μνήμη (x 1) να το αντιγράφουμε στην μνήμη (x2) να το συμπιέζουμε στην μνήμη (x 3) και στην συνέχεια να το γράφουμε στο δίσκο.
var fs1, fs2: TFileStream; begin fs1 := nil; fs2 := nil; try fs1:=TFileStream.Create('c:\fs1.dat',fmOpenRead or fmShareExclusive); fs2:=TFileStream.Create('c:\fs2.dat',fmOpenWrite or fmCreate); CompressStream(fs1, fs2); finally fs2.Free; fs1.Free; end; end;
Στο http://pages.cs.wisc.edu/~rkennedy/vmt αναλύεται πως επιτυγχάνεται πολυμορφισμός και μπορούμε να δηλώνουμε την Compress με ορίσματα τύπου TStream και να την χρησιμοποιούμε με ορίσματα τύπου TMemoryStream & TFileSTream.
Τι χρειάζεται ώστε ένα TFilestream να μπορεί να συμπιέζει όταν γράφει ή αντίθετα ? http://www.koders.com/delphi/fidD3C85C433D21324BD9C3C67620B9AAC15D243B9D.aspx?s=zip μας απαντάει το ερώτημα.
Πως αναγνωρίζουμε objects, μεθόδους και χαρακτηριστικά (attributes/properties). Ξεκινάμε με μία σύνοψη που περιγράφει το πρόβλημα. Τα ουσιαστικά, είναι υποψήφια objects. Αν υπάρχουν και στην πραγματικότητα τότε τα σιγουρεύουμε. Οι ιδιότητες ή τα χαρακτηριστικά τους είναι attributes (μνήμη) και οι μέθοδοι απαντούν σε μηνύματα και επενεργούν στη μνήμη του object.
Στις 16 Σεπτεμβρίου 1998 οι Rolling Stones εμφανίστηκαν στο ΟΑΚΑ. Είχα δουλέψει με τον PCL (πρόκειται μάλλον για επαγγελματική διαστροφή να αναφέρεσαι σε φίλο με το user name) για την προετοιμασία του λογισμικού υποστήριξης της συναυλίας. Το project αφορούσε 2 συναυλίες, στο ΟΑΚΑ και στο Λιμάνι στην Θεσσαλονίκη.
Τα εισιτήρια της συναυλίας ήταν προτυπωμένα με ολόγραμμα και barcode, σε αριθμημένα μπλοκάκια των 100 εισιτηρίων. Η εταιρεία …. ανέλαβε την διάθεση των εισιτηρίων και μέσω του call center της, επέτρεπε την κράτηση θέσεων σε διαφορετικές ζώνες του γηπέδου και με διαφορετική τιμή, πληρωμή με πιστωτική κάρτα, εμφακέλωση των εισιτήριων, αποστολή στους παραλήπτες, επικοινωνία και επαναποστολή σε περίπτωση αποτυχίας παράδοσης και τελικά έλεγχο του εισιτηρίου (μέσω του barcode) κατά την είσοδο στο γήπεδο.
Αναφέρω κάποιες κλάσεις που προκύπτουν από αυτή τη μικρή περιγραφή. 1. Το Venue (θέατρο, γήπεδο) που χωρίζεται σε θύρες/ζώνες. Κάθε θύρα έχει θέσεις, αριθμημένες ή όχι (αγωνιστικός χώρος) και μία τιμή. 2. Η παράσταση (Show), με την ημερομηνία, περιγραφή και το γήπεδο/θεάτρο. 3. Το block των εισιτηρίων με αναφορά σε ζώνη, τιμή εισιτηρίου και από-έως αριθμό εισιτηρίου. 4. Τα εισιτήριά που αντιστοιχούν σε θέση 5. Ο θεατής, με την διεύθυνση του, τον αριθμό της κάρτας του. 6. Την κράτηση ενός θεατή, με ημερομηνία κράτησης, παράσταση, ζώνη, αριθμό θέσεων και κόστος. 7. Τις θέσεις μιας κράτησης.
Η θέση του γηπέδου πρέπει να είναι μία κλάση και κάθε θέση ένα object ? (Υπάρχουν σπασμένες θέσεις ?)
Κάθε κλάση μπορεί να αποτελείται από άλλες (πχ Γήπεδο, θύρα, θέση) ή να συνδέεται με κάποια άλλη (πελάτης με κράτηση).
Οι κλάσεις αυτές αναφέρονται σαν PDC (Problem Domain Components).
Το αποτέλεσμα. http://www.tanea.gr/oikonomia/article/?aid=4034166 Εγώ πήγα αυθημερόν στις Βρυξέλες και είδα τον Larry Elison να μιλάει για το όραμα της Oracle αντί να ακούσω το Angie.
Πως αναγνωρίζουμε τις μεθόδους Είναι οι λειτουργίες μια κλάσης. Ξεκινούμε από τις βασικές λειτουργίες και καταλήγουμε στις ειδικές .
Έστω ότι έχουμε την παρακάτω κλάση
TSex = (sxMale,sxFemale);
TMammal = class private fAge : double; fWeight:double; fHeight:double; fSex:TSex; public constructor Birth; destructor Die; procedure Sleep; procedure Work; procedure Eat; property Age : double read fAge write fAge; property Weight:double read fWeight write fWeight; property Height:double read fHeight write fHeight; property Sex:TSex read fSex write fSex; end;
THuman = class(TMammal) public procedure Vote; end;
Είναι βέβαιο ότι ο καθένας θα μπορούσε να προσθέσει και πολλές άλλες λειτουργίες και χαρακτηριστικά. Η κλάση είναι μια προδιαγραφή. Επεκτείνεται και μεταβάλλεται. Στην κορυφή της κληρονομικής ιεραρχίας έχουμε πάντα τις γενικές λειτουργίες και προχωρώντας προς τα φύλλα καταλήγουμε στην εξειδίκευση των λειτουργιών.
Οθόνη καταχώρησης – απεικόνισης Στη συνέχεια πρέπει να σχεδιάσουμε τις οθόνες για την καταχώρηση των χαρακτηριστικών κάθε κλάσης - οντότητας. Οι ΑΠΛΕΣ οθόνες έχουν λίγα πεδία και λίγα χρώματα και χρησιμοποιούν ένα font χωρίς υπερβολές. Το απλό είναι δύσκολο.
Οι ανάγκες της εμφάνισης των δεδομένων είναι ανεξάρτητες από τα χαρακτηριστικά της κλάσης . Θα δημιουργήσουμε μία φόρμα για κάθε κλάση που θέλουμε να ενημερώσουμε.
Οι φόρμες κλάσεις αναφέρονται σαν HIC (Human Interaction Components). Το βρίσκω ισοδύναμο με τις HMI οθόνες /συσκευές που εμφανίζουν τα δεδομένα που συλλέγει το plc.
Για το γήπεδο θα υπάρχει η ΤVenueForm με γραφικά και δυνατότητα επιλογής θύρας. Η φόρμα θα δέχεται δεδομένα, θα τα ελέγχει για ορθότητα, και θα δημιουργεί μια PDC και ενημερώνει τα πεδία της.
Πως από την κλάση πάμε στη database ? «Υπάρχει η Oracle και text files». Το είχε πει πριν από χρόνια, το 1998, ο Βασίλης και παραμένει δυστυχώς αλήθεια. Από την άλλη η M$oft με τον sqlserver δημιούργησε την db για τις μάζες. Έγραφες ένα select * from table και τα αποτελέσματα εμφανιζόταν σε ένα εξαιρετικό εργαλείο. Κανένας δεν νοιαζόταν για performance και ότι οι writers μπλοκάρουν τους readers.
Αρχικά αντιστοιχούμε κάθε κλάση σε ένα πίνακα. Κάθε πίνακας πρέπει να έχει πρωτεύον κλειδί. Χρησιμοποιούμε, ένα χαρακτηριστικό που είναι μοναδικό (πχ ΑΦΜ σε πελάτες) ή ένα κρυφό τεχνητό κλειδί (surrogate key). Επιλέξτε ένα μικρό κλειδί (ένα 32 bit integer). Μην χρησιμοποιείτε Guids. Σταματήστε την άσκοπη χρήση χώρου και υπολογιστική ικανότητας. Οι πίνακες συνδέονται μεταξύ τους με κλειδιά (Foreign Keys). Χρησιμοποιήστε τα. Δηλώστε στη βάση όλους τους κανόνες ή περιορισμούς (constraints) που ορίζονται για το δεδομένα σας.
Η DMC κλάση (Data Management Component) επικοινωνεί με μία PDC κλάση και παράγει τις κατάλληλες SQL εντολές για να ενημερώσει την database.
H DMC κλάση «τρέχει» δίπλα στην database, παράγει 1..Ν sql εντολές και μέσω του database client (Oracle OCI ή M$oft dblib) τις στέλνει με TCP/IP προς εκτέλεση στον database server. Οι καταχωρήσεις στην βάση γίνονται πάντα σε επίπεδο οντότητας και να προστατεύεται η ακεραιότητα των δεδομένων χρησιμοποιούνται transactions. Τα transactions έχουν ΑΥΣΤΗΡΑ μικρή διάρκεια. Δηλαδή, δεν εμφανίζουμε ερωτήσεις ενώ έχουμε ξεκινήσει ένα transactions ή δεν εκτυπώνουμε μέσα σε transaction.
Αποφεύγουμε τα deadlocks. Αν σε ένα ενεργό transaction ενημερώνουμε τις εγγραφές με PK A και Β και σε ένα δεύτερο ταυτόχρονο transaction τις B και Α τότε το ένα transaction θα κλειδώσει το άλλο.
Κάποια στιγμή μου ζητήσανε βοήθεια για ένα πρόβλημα deadlock που εμφανιζόταν σε μία Oracle. Δύο σταθμοί καταχωρούσαν μεγάλες παραγγελίες και που & που κωλούσαν. Ρώτησα αν ταξινομούσαν τις γραμμές τις παραγγελίας πριν την καταχώρηση. Client Server ή 3 Tier Η εφαρμογή μας περιέχει τις HIC, PDC & DMC κλάσεις και τρέχει σένα PC. Ένα δίκτυο 100 Mbits μας συνδέει με την βάση δεδομένων. Όταν λοιπόν εισάγουμε στην οθόνη 1 κράτηση με 100 θέσεις θα πρέπει να την καταχωρήσουμε στην βάση με χρήση 101 εντολών “insert into table column list values list” μέσα σε ένα begin transaction & commit transaction.
Τι γίνεται όταν η εφαρμογή μας τρέχει στην Κομοτηνή και η database είναι στον Άγιο Στέφανο. Θα πρέπει η εφαρμογή μας να σπάσει σε HIC & PDC που «τρέχουν» στην Κομοτηνή και το DMC να βρεθεί δίπλα στην database στον Άγιο Στέφανο.
Η διαχειριστική εφαρμογή δέχεται ή παράγει δεδομένα, σχηματίζει ένα μήνυμα με αυτά (κωδικοποιημένο πιθανά σαν xml) και το στέλνει στο PDC στο Άγιο Στέφανο. Εκεί, ένας xml to sql maper http://stackoverflow.com/questions/1702535/xml-to-sql-mapping καταχωρεί τα δεδομένα στην βάση δεδομένων και ενημερώνει τον χειριστή για την επιτυχία / αποτυχία της καταχώρησης.
«Στέλνει το μήνυμα στον Αγιο Στέφανο». Ποιος όμως το παραλαμβάνει ?
Application Server Μιλάμε για έναν application server, αν χρησιμοποιούμε δικά μας μηνύματα ή ένα Web Server που υποστηρίζει http πρωτόκολλο (internet) με xml περιεχόμενο.
Ξαφνικά ένας open source Apache Web Server μπορεί άνετα να χρησιμοποιηθεί (ξέρω, έχουμε φύγει λίγο από το Delphi).
Ti κοινό έχουν ένας application Server, o Web Server και ο database server. Ακούνε σε μία πόρτα για συνδέσεις, δέχονται πολλαπλές συνδέσεις μέσω TCP/IP από πελάτες που ξέρουν να τους μιλήσουν, δημιουργούν ένα ανεξάρτητο νήμα (thread) εξυπηρέτησης κάθε σύνδεσης και ανταλλάσουν μηνύματα με το πελάτη για όσο διάστημα διαρκεί η σύνδεση.
Ένας Delphi application server δέχεται custom μηνύματα, και στο thread του πελάτη (Κομοτηνή) δημιουργεί το κατάλληλο PDC object που μεταφράζει το μήνυμα σε sql και τα καταχωρεί στην βάση. Ένας Apache δέχεται http μηνύματα, αποσπά το xml και μέσω php το καταχωρεί στην βάση. Ένας database server, δέχεται μηνύματα μέσω του database client, και μπορεί να εκτελέσει sql εντολές.
The Delphi Way Το Delphi προχώρησε ένα βήμα παραπάνω επεκτείνοντας την γλώσσα Pascal ώστε η γραμματική της να επιτρέπει την δήλωση κλάσεων και πρόσθεσε ένα εξαιρετικά παραγωγικό και γρήγορο περιβάλλον εργασίας για την δημιουργία προγραμμάτων. Υποστήριξε μάλιστα και κληρονομικότητα στις φόρμες της εφαρμογής. Με χρήση data aware components μπορείς, ξεχνώντας όλα τα παραπάνω, να μεταβάλεις απευθείας τα δεδομένα της βάσης. Tragic. Όλοι μπορούσαν να φτιάξουν πολύ γρήγορα διαχειριστικές ή άλλες εφαρμογές. Χωρίς ανάλυση ή μεθοδολογία. Η κάθε φόρμα, έβλεπε τις υπόλοιπες, ο κώδικας χειρισμού της οθόνης, έμπλεκε με τους υπολογισμούς και με την αποθήκευση/ανάκληση από τον βάση δεδομένων. Μια μεταβολή σε κάτι φαινομενικά απλό επιδρούσε σε κάτι άσχετο.
Ρίξτε μια ματιά σε ένα τελευταίο σας project. Μετρήστε τις απλές ρουτίνες, έξω από objects και τις global μεταβλητές. Τι θα σας προσφέρουν τα objects. Δυσκολότερη αρχική υλοποίηση (χρειάζεται σκέψη), ευκολότερη συντήρηση, μεγαλύτερη επεκτασιμότητα λιγότερα bugs.
|
 |
|
|
Pirate
Advanced Member
    
Greece
3177 Posts |
Posted - 27 July 2012 : 11:53:23
|
Μιας και γράφω από pda διότι: «πρώτο καλοκαίρι μετά από 18 χρόνια που δεν πήρα το portable παραμάσχαλα στις διακοπές, άρα Νίκη μεγάλη...» θέλω να πω ένα μπράβο στον pfys για την ανάπτυξη αυτή που δείχνει ότι μπήκε με 1000 στο OOP, αλλά ταυτόχρονα και το επικήδειο ρέκβιεμ για μια πολύ μεγάλη γλώσσα προγραμματισμού την οποία πεθάνανε με το ζόρι προς δόξα άλλων όχι αναγκαστικά καλύτερων...
Του αφιερώνω αυτό από τον καιρό του 1993 όταν διάβαζα όλες αυτές τις στρυφνές έννοιες μόνος και δίχω δάσκαλο... OOP & Ελληνική γλώσσα σε όλο της το μεγαλείο
και το παρατηρείστε το ωραιότερο: Προς Αμερικανούς αναγνώστες: Τι σημαίνει Polymorphism... Polymorphism is Greek "for many shapes" and it is just that: a way of giving an action...
Τι σημαίνει Πολυμορφία; Για τους Έλληνες δεν χρειάζεται ιδιαίτερη εξήγηση τι σημαίνει πολυμορφία. Από πολλές πηγές μας αν ανατρέξουμε π.χ. στο δωδεκάθεο θα δούμε ότι οι Θεοί έπαιρναν συνήθως διαφορετικές μορφές στην επικοινωνία τους με τους θνητούς. Μπορούμε να πούμε ότι είχαμε πολύμορφους θεούς κι απ' ότι φαίνεται αυτή η ιδιότητα άρεσε στον κόσμο. Για τα Delphi objects η πολυμορφία είναι μία ζηλευτή ιδιότητα όπου επιτρέπει στο ίδιο αντικείμενο με τα κοινά χαρακτριστικά π.χ. στη γάτα κλάσης TGata να περιέχει μία ακόμη ιδιότητα π.χ. KaloGataki η οποία είναι τύπου TKaloGataki ο οποίος παίρνει π.χ. τις τιμές: kgGourgourizon, kgKakistro, kgGriniazon, kgKleftizon Συνεπώς το ίδιο το object που περιγράφει μια γάτα, μπορεί να συμπεριλάβει πολλούς τύπους γατιών διότι encapsulates εκτός των άλλων π.χ. χρωματισμών τριχώματος, χρωματισμό ματιών κλπ. μία ακόμα ιδιότητα που είναι τύπου «καλό γατάκι». Από κει και μετά έρχεται η κληρονομικότητα η οποία σου επιτρέπει να φτιάξεις μία άλλη κλάση γάτας πχ την TSiamGata η οποία είναι κλάσης TGata και επομένως μονομιάς κληρονομεί όλες τις ιδιότητες αυτής επομένως και την KaloGataki. Ταυτόχρονα επιτρέπει στον προγραμματιστή να προσθέσει στη νέα κλάση ιδιότητες που δεν βλέπει η πρόγονη κλάση. Για παράδειγμα την ιδιότητα: Oura τύπου TOura ο οποίος παίρνει τις τιμές: gStraviOura, gHorisOura, gNormalOura
Περιττό να προσθέσω ότι η ιδέα των objects είναι απόρροια των φοβερών records της Pascal. Το ηλιακό μου πρόγραμμα βασίσθηκε σε 3 τέτοια records που δόμησα όπως TSunData, THliakosStruc, TBoilerStruc. Για παράδειγμα η θερμοκρασία εξόδου από τον συλλέκτη είναι ιδιότητα του THliakosStruc ή η θερμοκρασία εισόδου στον εναλλάκτη του boiler είναι ιδιότητα του TBoilerStruc
Δυστυχώς όμως.... Σ' αυτόν τον κόσμο τον κακό, τον χιλιομπαλλωμένο, ό,τι καλό πεθαίνει!
Φευγάτος Πειρατής
Στίγμα Μαστροκαπετάνιου |
Edited by - Pirate on 27 July 2012 11:57:50 |
 |
|
|
pfys
New Member

Greece
105 Posts |
Posted - 27 July 2012 : 15:10:10
|
Πραγματικός κόσμος Θέλω να βάλω ένα καλοριφέρ στο σπίτι μου. Πέντε σωματάκια και ένα μπόιλερ θα βάλω. Έχω μάστορα διαμάντι. Γιατί να πληρώσω τον μηχανολόγο ?
Ακούγεται γνώριμο ?. Ισχύει παντού. Η μεθοδολογία υπάρχει και αν θέλουμε την χρησιμοποιούμε. «Τι έχεις καρδιά μου και αναστενάζεις. Το κεφάλι τα κάνει το κεφάλι τα τραβάει» όπως μου έλεγε, από μικρό, ο πατέρας μου.
Έστω ότι πρέπει να καταχωρήσουμε τα στοιχεία ενός πελάτη σύμφωνα με την μεθοδολογία. Έχουμε ετοιμάσει την PDC κλάση ΤCustomer που περιγράφει το τι είναι ο πελάτης.
TCustomer = class private FCUSTID:Integer; FFNAME:String; FLNAME: String; FLASTPICKUP: String; FAFM: String; FADDRSTR: String; FADDRNUM: String; FADDRZIP: String; FADDRCITY: String; FTEL1: String; FTEL2: String; FCOMPANY: String; FPROFESSION: String; FDOY: String; Protected // δημιουργεί νέα Ιd για τον πελάτη procedure SetCustId(value:integer); // Ελέγχει αν το ΑΦΜ που καταχωρούμε είναι σωστό. procedure SetΑFM(const value:string);
public Property CUSTID:Integer read FCustId write SetCustId; Property FNAME:String read FFName write FFname; Property LNAME:String read FLName write FLname; Property AFM:String read FAFM write SetAFM; ... End;
Έχουμε ετοιμάσει και την DMC κλάση TDMCustomer =class(ΤCustomer) Public // Δημιουργεί ένα πελάτη και ανακαλεί τα στοιχεία του από την βάση. Constructor Create(ID:integer); Procedure Save; Procedure Update; End; Έχουμε σχεδιάσει την οθόνη καταχώρησης
https://picasaweb.google.com/107823581317170981756/July272012?authkey=Gv1sRgCKmIkMi845uYSA#5769803951973481138
Η TCustForm επικοινωνεί με την ΤCust για να εμφανίσει ή να μεταβάλει τα στοιχεία ενός πελάτη. Η TCust με την TDMCust για να ανακαλέσει ή να αποθηκεύσει τα δεδομένα στην βάση δεδομένων.
Ας δούμε τις «ευκολίες» του Delphi. Τα data aware components επιτρέπουν
1. Την σύνδεση με πίνακα της βάσης και ορισμό των χαρακτηριστικών της γιαλαντζί κλάσης, από όλα τα πεδία της βάσης. 2. Την δυνατότητα μεταβολής των δεδομένων 3. Την αυτόματη ενημέρωση της βάσης.
Ας αφήσουμε τις διαχειριστικές εφαρμογές και ας δούμε την εφαρμογή του πειρατή.

Τα ουσιαστικά δηλώνουν τα objects. Πολύ περισσότερο όταν υπάρχουν και φυσικά. Τα ρήματα δηλώνουν μεθόδους/λειτουργίες.
Ο ήλιος ακτινοβολεί συγκεκριμένη ενέργεια ανάλογα με την περιοχή και την ώρα.
TSunEnergy = class Public Function EnergyFlow:Double; // ακτινοβολεί.. Property Month Property Day End;
Ο ηλιακός συλλέκτης αποφορά την ενέργεια, και την μετατρέπει σε θερμική
TSolarPanel = class public property Slope :double; //κλίση property SouthDeviation:double; // Απόκλειση από τον Νότο property Surface:double; // συλλεκτική επιφάνεια property Flow:double; // Lt/h property GlycolePerc : double; end;
Το boiler μέσω του εναλλάκτη για τον ηλιακό, ζεσταίνει το νερό που περιέχει
ΤBoiler = class public property Volume:double; property AverageDaylyConsuption:double; property WaterTemperature:double; property SolarHeatExchangeSurface :double; // m2 end;
H κλάση TCalculator υπολογίζει ένα σύνολο τιμών,
για μία ημερομηνία aDate, από ώρα FromTime έως ToTime με βήμα step λεπτά για τον συλλέκτη aSolarPanel και το boiler aBoiler.
TCalculator = class procedure Calc(aDate:TDate; // για συγκεκριμένη ημερομηνία FromTime, ToTime:TTime; step: integer; aSolarPanel:TSolarPanel; aBoiler:TBoiler); property CalcCount:integer; property Time[index:integer]:TTime; // property SunHeight[index:integer]:degrees; property SunAzimou8io [index:integer]:degrees; property BoilerTemp [index:integer]:double; property CollectorTempIn [index:integer]:double; property CollectorTempOut [index:integer]:double; ... end;
Τα αποτελέσματα εμφανίζονται στην οθόνη
For i:=0 to Calculator.CalcCount do begin Grid[0,i]:= FormatTime(Calculator.Time[i]); Grid[1,i]:= FormatDegrees(Calculator.SunHeight [i]); Grid[2,i]:= FormatDegrees(Calculator.SunAzimou8io [i]); Grid[3,i]:= Format('%.1f',[Calculator.BoilerTemp [i]]); Grid[4,i]:= Format('%.1f',[Calculator.CollectorTempIn[i]]); Grid[5,i]:= Format('%.1f',[Calculator.CollectorTempOut[i]]); ... End;
κάθε κλάση ορίζεται σε ξεχωριστό unit. Η φόρμα γνωρίζει μόνο τον Calculator.
Εδώ, συνάδελφοι μηχανολόγοι, χρειάζομαι την βοήθεια σας για το ολοκληρώσουμε το μοντέλο. Χρειάζομαι τις προτάσεις σας για τα επιπλέον χαρακτηριστικά των κλάσεων και τις μεθόδους/υπηρεσίες που παρέχουν.
ΥΓ. 1. Εγραφα και αφου τελείωσα είδα την απάντηση του πειρατή. Προκύπτει απόλυτη σύμπτωση στην ανάλυση. Μπορεί να τον καταφέρω να το ξαναγράψει με objects 
2. Περίμενα οτι θα υπήρχαν κάποιοι, που θα διαφωνούσαν με τον ορισμό του THuman με μόνο λειτουργία την ψήφο. Υπήρχαν άλλες πολύ πιο σημαντικές (Ερωτας, διανόηση, επικοινωνία). 
|
 |
|
|
pfys
New Member

Greece
105 Posts |
Posted - 27 July 2012 : 15:30:23
|
quote:
«πρώτο καλοκαίρι μετά από 18 χρόνια που δεν πήρα το portable παραμάσχαλα στις διακοπές, άρα Νίκη μεγάλη...»
Δεν φαντάζομαι, η μεγάλη Νίκη να είναι κάποια παλιά συμμαθήτρια ?  |
 |
|
|
Pirate
Advanced Member
    
Greece
3177 Posts |
Posted - 27 July 2012 : 17:21:12
|
quote: Δεν φαντάζομαι, η μεγάλη Νίκη να είναι κάποια παλιά συμμαθήτρια ?
Πάλι θα απαντήσω από pda γιατί «ξέρεις να με προκαλείς»... 1. Η Νίκη η συμμαθήτρια πάει, χάθηκε! Και καλύτερα που χάθηκε για να μη με δει έτσι όπως με κατάντησε το άλλο μου πάθος (δείγμα παραπάνω) με την 25χρονη παραμονή μου σε καρέκλα μπροστά από τον δαίμονα που λέγεται PC. Εκτοξεύθηκε ο νους και γκρεμοτσακίσθηκε το σώμα! Συν 60 κιλά! Καλύτερα να μη με δει η Νίκη διότι θα χάσει πάσα ιδέα για τον γνώριμό της και πολυαγαπημένο συμφοιτητή που ήξερε να την ταξιδεύει δίχως τα objects της Pascal μιας και τότε δεν τα γνώριζα καν. ΠΡΟΣΟΧΗ λοιπόν σε σας τους νεώτερους. Πρώτα το σώμα και μετά ο νους! Καμία γνώση δεν είναι αυτοσκοπός όσο και να μας καταξιώνει. Άλλωστε εμείς οι Έλληνες το γνωρίζουμε καλά με το γνωστό «νους υγιής εν σώματι υγιή» 2. Η Νίκη για την οποία μιλάω είναι κι αυτή θυλυκού γένους και θα μπορούσε να είναι μια ωραία γυναίκα για να μου κεντρίσει το ενδιαφέρον να κλείσω πλέον τον «δαίμονα». Το έχω βάλει στοίχημα με τον εαυτό μου και θα το πετύχω. Θέλω να πάρω πίσω από τα 60 κιλά όσα μπορέσω κι ας μείνουν όσα μείνουν. Ικανά όμως να έλξουν την άλλη Νίκη, την παλιά μου συμμαθήτρια
Συνεπώς: quote: Μπορεί να τον καταφέρω να το ξαναγράψει με objects
Κάνε λίγο υπομονή. Έχω τον γιο μου πρωτοετή στο ΕΜΠ σπασικλάκι κανονικό με δεκάρια κι έτσι. Και στον προγραμματισμό! Μόνο που στους Μηχανολόγους τους «αλωνίζουν» με την Fortran και έχει τα νεύρα του αν και του λέω να μάθει κι αυτήν. Έτσι κι αλλιώς στο να γράψεις κώδικα δεν μετρά η γλώσσα αυτή καθεαυτή όσο το ταλέντο σου να συνθέτεις «γλωσσικούς μηχανισμούς» οι οποίοι τρέχουν άψογα και δίχως προβλήματα. Θα σε φέρω σε επαφή μαζί του και φιάξτε όσα objects τραβάει η όρεξή σας. Είναι C++ακιας αλλά τον έχω πιάσει να υποκλέπτει τις συναρτήσεις του SysUtils 
Στίγμα Μαστροκαπετάνιου |
 |
|
|
pfys
New Member

Greece
105 Posts |
Posted - 04 August 2012 : 13:06:15
|
Απαντάω από την βόρεια Εύβοια, με το άρτι αποκτηθέν Aurdino έτοιμο για πειράματα.
quote:
Έχω τον γιο μου πρωτοετή στο ΕΜΠ σπασικλάκι κανονικό με δεκάρια κι έτσι.
Μάλλον ο γιος σου δεν είχε που να μοιάσει. Εύχομαι στον λεβέντη σου, κάθε επιτυχία. Ελπίζω μόνο να μην μελετάει μόνο για heat tanks αλλά να εκμεταλλευθεί στο έπακρο και το διαθέσιμο οικογενειακό think tank.
"Αιέν αριστεύειν και υπείροχον έμμεναι άλλων, μηδέ γένος πατέρων αισχυνέμεν». Πάντα να είσαι πρώτος και ανώτερος από τους άλλους και να μην ντροπιάζεις τη γενιά των προγόνων. Ιλιάδα, Ζ 208
quote:
Μόνο που στους Μηχανολόγους τους «αλωνίζουν» με την Fortran και έχει τα νεύρα του αν και του λέω να μάθει κι αυτήν
http://www.computer.org/csdl/mags/co/2012/07/mco2012070008.html
quote:
Έτσι κι αλλιώς στο να γράψεις κώδικα δεν μετρά η γλώσσα αυτή καθεαυτή όσο το ταλέντο σου να συνθέτεις «γλωσσικούς μηχανισμούς» οι οποίοι τρέχουν άψογα και δίχως προβλήματα.
Η γλώσσα είναι το εργαλείο. Πρέπει να υποστηρίζει τις απαιτούμενες δυνατότητες. Η fortran, η C και η turbo pascal δεν υποστηρίζουν τους μηχανισμούς για να δηλώσεις κλάσεις και να υλοποιήσεις (instantiate) αντικείμενα.
Η σύνθεση, από απλούστερα ή δομικά αντικείμενα οδηγούν σε κατασκευές, γλωσσικές ή μη, που επιλύουν ένα πρόβλημα. (bottom-up).
Η ανάλυση, «σπάει» ένα σύνθετο αντικείμενο ή πρόβλημα, στα συστατικά του και το επιλύει επιλύοντας τα επιμέρους μικρότερα προβλήματα. (top-down)
quote:
Περιττό να προσθέσω ότι η ιδέα των objects είναι απόρροια των φοβερών records της Pascal. Το ηλιακό μου πρόγραμμα βασίσθηκε σε 3 τέτοια records που δόμησα όπως TSunData, THliakosStruc, TBoilerStruc. Για παράδειγμα η θερμοκρασία εξόδου από τον συλλέκτη είναι ιδιότητα του THliakosStruc ή η θερμοκρασία εισόδου στον εναλλάκτη του boiler είναι ιδιότητα του TBoilerStruc
Συμφωνώ, αλλά παρέλειψες τις ρουτίνες που χρησιμοποιούν τα records. Αυτό που προκύπτει και από τα δύο, το object δηλαδή, λειτουργεί σαν κάτι ενιαίο. Ενσωματώνει (encapsulates) δεδομένα και υπολογισμούς.
Επιστρέφω, στο πρόγραμμά σου γιατί αποτελεί, με δεδομένο το κοινό, το καλύτερο παράδειγμα αλλαγής από δομημένο σε αντικειμενοστρεφή προγραμματισμό.
To εγχειρίδιο των Ηλιακών συστημάτων http://www.monachos.gr/forum/topic.asp?TOPIC_ID=3832 αποτελεί μια πολύ καλή περιγραφή των φαινομένων. (stom ευχαριστώ)
Ο ήλιος ακτινοβολεί συγκεκριμένη ενέργεια ανάλογα με την περιοχή και την ώρα.

TSunEnergy = class
Public
// Ηλιακή ενέργεια στο συγκεκριμένο GeoPlatos, ημέρα και ώρα σε W/m2
function Energy:Double; overload;
// με μεταβλητή την ώρα σε W/m2
function Energy(aTime:integer):Double; overload;
property Time:integer; // seconds since midnight
property Month:integer;
property Day:integer;
property GeoPlatos:double;
property SunPerc:double;// Συντελεστής ηλιοφάνειας
End;
Η ροή ενέργειας είναι το μόνο στοιχείο της ηλιακή ακτινοβολίας που ενδιαφέρει ένα panel. Τα υπόλοιπα στοιχεία είναι παράμετροι που χρειάζονται για τον υπολογισμό της ροής ενέργειας.
Η δήλωση της κλάσης γίνεται στο ανεξάρτητο uSunEnergy.pas
Ο ηλιακός συλλέκτης αποφορά την ενέργεια, και την μετατρέπει σε θερμική μέσω του ρευστού του κλειστού κυκλώματος.
TSolarPanel = class
public
function Energy(EnergyIn):double; // συνολική για όλη την επιφάνεια kWh
function Flow:double; // ροή Lt/h
property SolarAbsorbtion:double; // ποσοστό απορρόφησης ηλιακής ενέργειας
property Slope :double; //κλίση ηλιακού
property SouthDeviation:double; // Απόκλειση από τον Νότο
property Surface:double; // εμβαδόν συλλεκτικής επιφάνειας
property Efficiency:double; // απόδοση ηλιακού
property GlycolePerc : double;
property WaterInTemperature:double; // θερμ. εισόδου κλειστού κυκλώματος
property WaterOutTemperature:double; // θερμ. εξόδου κλειστού κυκλώματος
end;
H TSolarPanle.Energy δέχεται σαν παράμετρο την εισερχόμενη ενέργεια και υπολογίζει την αποδιδόμενη ενέργεια. Η ώρα της ημέρας είναι παράμετρος της TSunEnergy και όχι του panel.
Η δήλωση της κλάσης γίνεται στο ανεξάρτητο uSolarPanel.pas
Το boiler μέσω του εναλάκτη για τον ηλιακό ή του εναλάκτη για τον λέβητα ή την ηλεκτρική αντίσταση, ζεσταίνει το νερό που περιέχει
THeatSource = (hsSolarPanel, hsBurner, hsElectricity)
ΤBoiler = class
public
// κάνω την παραδοχή οτι μόνο μία πηγή ενέργειας τροφοδοτεί το boiler
function Heat(inEnergy:double; from:THeatSource):double; // στιγμιαία ισχύς Kw
function AccumulatedEnergy:double; // από το περιεχόμενο ζεστό νερό Kwh
function SolarFraction:double; // ποσό ενέργειας απο ηλιο / ποσό ενέργειας κατανάλωσης
property WaterVolume:double;
property AverageDayConsuption:double; // lt
property WaterInTemperature:double; // ανάλογα με την εποχή.
property WaterOutTemperature:double; // ανάλογα με την εποχή.
property SolarHeatExchangeSurface :double; // m2
property BurnerHeatExchangeSurface :double; // m2
end;
To boiler συσσωρεύει θερμότητα και αποδίδει λίτρα ΖΝΧ σε συγκεκριμένη θερμοκρασία στην μονάδα του χρόνου.
Η δήλωση της κλάσης γίνεται στο ανεξάρτητο uBoiler.pas
Όλα τα objects σχεδιάστηκαν για να δίνουν στιγμιαίες τιμές. Για να παράξουμε τα διαγράμματα ακτινοβολίας θα πρέπει να καλέσουμε την TSunEnergy.Energy(aTime) με όρισμα χρόνους που διαφέρουν μεταξύ τους κατά 15 min.
H κλάση TCalculator γνωρίζει όλα τα παραπάνω αντικείμενα (TSunEnergy, TSolarPanel, ΤBoiler) βλέπει (uses) τα uSunEnergy.pas, uSolarPanel.pas, uBoiler.pas και υπολογίζει
ένα σύνολο τιμών,
για μία ημερομηνία aDate, από ώρα FromTime έως ToTime με βήμα step λεπτά για τον συλλέκτη aSolarPanel και το boiler aBoiler.
TCalculator = class
procedure Calc(aDate:TDate; // για συγκεκριμένη ημερομηνία
FromTime, ToTime:TTime; step: integer;
aSolarPanel:TSolarPanel;
aBoiler:TBoiler);
property CalcCount:integer;
property Time[index:integer]:TTime; //
property SunHeight[index:integer]:degrees;
property SunAzimou8io [index:integer]:degrees;
property BoilerTemp [index:integer]:double;
property CollectorTempIn [index:integer]:double;
property CollectorTempOut [index:integer]:double;
...
end;
Στο επόμενο post θα αναφερθώ στα threads, την βασική οντότητα που εκτελεί το CPU.
|
 |
|
|
stom
Senior Member
   
Greece
1665 Posts |
Posted - 05 August 2012 : 10:15:50
|
Ποσο βορεια δλδ? Χτες ημουν στο πηλι..
Arduino στις διακοπες. Τι να πω.. Εγω παλι κουβαλαω κατευθυντικες yagi κεραιες για τους 2,4....
Συνηθως ολο και καποιο wifi βρισκεται και βολευομαστε ολοι.
Στηνεται ενα laptop σε repeater mode και βολευομαστε ολοι. Τηλεφωνα, laptop, psp και δεν συμμαζευεται..
Και για να μην παιδευομαστε... http://seventhgate.codeplex.com/
ΥΓ sorry για το ασχετο post.... αλλα το μονο σχολιο ειναι πως θα παντρεψεις το arduino και την object pascal?
Burn baby, burn |
 |
|
|
pfys
New Member

Greece
105 Posts |
Posted - 05 August 2012 : 12:14:14
|
quote: Ποσο βορεια δλδ?
Στο Νέο Πύργο, δίπλα στους Ωρεούς
πως θα παντρεψεις το arduino και την object pascal?
Εχω τελειώσει ένα project με Delphi και επικοινωνία με modbus over TCP/Ip με ένα slave PLC S1200. Μου ζητήθηκε να προτείνω εναλακτικό h/w.
Eυτυχώς υπάρχει η γλυκιά C. Δεν μπορείς να πας πιο κοντά στην assembly με άλλη γλώσσα. Εγραφα με Zortech C compiler το 1989. Μετά βγήκε η καταπληκτική Borland C/C++ (386 instructions, code optimizations). Και μετά ξύπνησε ο M$oft και τους έκλεισε όλους.
|
 |
|
|
stom
Senior Member
   
Greece
1665 Posts |
Posted - 05 August 2012 : 13:37:05
|
Απο οτι βλεπω, υπαρχει ετοιμο modbus slave για arduinia.. Αμα ο κοσμος εχει ορεξη και χρονο.. Δεν το ψαξα, αλλα ισως υπαρχει και σε master. Αλλα αμα εχεις το μαχαιρι και το καρπουζι, υλοποιεις οτι θες.
Εχεις βρει κανα τροπο να μεταφερεις το αποτελεσμα της object pascal σε περιβαλλον εκτος windows? Χωρις τυχον παραθυρικο..
Τα windows για αυτοματισμο χαμηλου επιπεδου ειναι καπως δυστροπα...
Προβλεπω οτι συντομα η καλυτερη πλατφορμα αυτοματισμου θα ειναι android based...
Burn baby, burn |
 |
|
|
pfys
New Member

Greece
105 Posts |
Posted - 05 August 2012 : 22:44:17
|
quote: Τα windows για αυτοματισμο χαμηλου επιπεδου ειναι καπως δυστροπα...
Συμφωνώ, τα winda κατάφεραν να γίνουν λειτουργικό στην έκδοση ΝΤ. Ακόμα και τότε όμως η εκτύπωση ενός μεγάλου αρχείου έπαιρνε όλη την μνήμη και γονάτιζε τις υπόλοιπες εφαρμογές. Ακόμη και σήμερα ένα reboot κάθε τόσο τα "στρώνουν".
Αναφορικά με την εμφάνιση (user interface) νομίζω ο Jobs στην ομιλία του στο Standford τα λέει όλα.
quote: Εχεις βρει κανα τροπο να μεταφερεις το αποτελεσμα της object pascal σε περιβαλλον εκτος windows? Χωρις τυχον παραθυρικο..
Η συλλογή δεδομένων γίνεται σε windows service, χωρίς οθόνη κτλ. Ενημερώνεις τα αποτελέσματα στην μνήμη όταν παράγονται και σε αρχείο και 1. τα «φωνάζεις» περιοδικά στο καλώδιο με UDP data έως 1,5k. http://www.cyberciti.biz/tips/linux-netconsole-log-management-tutorial.html
2. μέσω κοινής (shared) μνήμης όπως η Win32 outputdebugstring http://www.codeproject.com/Articles/23776/Mechanism-of-OutputDebugString δες τον δέκτη (debugview) http://technet.microsoft.com/en-us/sysinternals/bb842059.aspx
3. γίνεσαι εκδότης (publisher) και δέχεσαι TCP/IP συνδέσεις από συνδρομητές και τους διαθέτεις τα δεδομένα.
4. Γράφεις τα δεδομένα σε μία database και τα διαβάζουν οι ενδιαφερόμενοι.
quote:
Προβλεπω οτι συντομα η καλυτερη πλατφορμα αυτοματισμου θα ειναι android based...
Mobile + core linux + Open Source + Java ή FPC + Java GUI API Αν προσθέσεις και optoisolated I/O και μια αξιοπρεπή τροφοδοσία. και νέα APIs για να μάθουμε..
Θα αλώσει και το latop/desktop περιβάλλον ? Δέχεσαι τα αρχεία σου να είναι στο συννεφάκι και να τα προσπελαύνεις από παντού ? |
 |
|
|
stom
Senior Member
   
Greece
1665 Posts |
Posted - 06 August 2012 : 09:59:29
|
Το αν δεχομαι τα data μου στο cloud λιγη σημασια εχει. Η μεγαλη μαζα παραμενει clueless.. Ασε που τα εχει χασει 5-6 φορες μιας και η λεξη backup ειναι αγνωστη. Εχω εφαρμοσει κοινοχρηστα στο cloud, και ολοι ειναι happy... Ολα τα δελτια συντηρησης βρισκονται εκει. Οποιος θελει, μπαινει και τα βλεπει. Οπως και εγχειριδια, σχεδια κλπ.
Βεβαια το δικο μου λεβητοστασιο εχει din rail ethernet switch και συντομα θα εχει και wifi access point οποτε δεν ειμαι τυπικη περιπτωση. (αμα εισαι κατω και θες να δεις μια λεπτομερια στο manual του καυστηρα πχ, ανοιγεις το κινητο, και κατεβαζεις το pdf του κατασκευαστη από το wifi...) Αλλιως πρεπει να ανεβεις επανω, να τυπωσεις και να ξανακατεβεις. Μονο μειονεκτημα οτι θελει καθαρα χερια.)
Το μοντελο που περιγραφεις ειναι λιγο μεγαλο. Βεβαια οποιος το χρειαζεται, το χρειαζεται λογω μεγεθους... Σε μικροτερες εγκαταστασεις, οπως λεβητοστασια, εξυπνα σπιτια κλπ μαλλον χρειαζομαστε κατι λιγοτερο. Τυπικα ενα αξιοπιστο multitasking os, ενα καλο tcp/ip stack και ενα ευκολο web server based διαχειριστικο. Ακομα και για databases, για απλα πραγματα, οι textuριες δουλευουν μια χαρα.
Το laptop περιβαλλον εχει αλλωθει. Ξεκινησαμε με τα netbook, πηγαμε στα tablet και τωρα που πεφτει το κοστος θα γινουν mainstream. Το δειχνουν και οι πωλησεις εξαλλου. Και αυτη η προσεγγιση ταιριαζει γαντι στη λογικη του cloud. Η μηπως το cloud ειναι που τα κανει τοσο πετυχημενα? Μαλλον και τα δυο.
Το linux εχει αποτυχει ως desktop. Ο λογος ειναι απλος. Πανσπερμια διανομων, και περιστασιακη υποστηριξη απο τους κατασκευαστες hardware. Το τι δουλευει απο περιφερειακα ειναι περισσοτερο θεμα τυχης. Αν δεν, το μονο που μενει ειναι να γραψεις ΜΟΝΟΣ σου τους drivers. Καληνυχτα linux desktop
Το computing για τις μαζες θα ερθει μεσω ενος κινητου πηγμενου στα αναβολικά. Ξεχειλωνει η οθονη, μεγαλωνει η flash, αυξανεται η μνήμη, ανεβαινει η αναλυση, και καταληγουμε σε ενα υπολογιστη on steroids... Ομως εντωμεταξυ η συμβατοτητα με τα windows εχει περιορισθει στα αρχεια του office...
Η Microsoft θα ειναι η νεα Novell. Για οποιον την θυμαται.
Η Apple προσπαθει με νυχια και δοντια να μας πεισει οτι ολη η ιδεα του cloud computing ειναι (κατ επεκταση)δικια της. Προσπαθει να πνιξει το android για να πουλαει μονο τα απαραδεκτα υπερτιμημενα προϊόντα της.
Η Microsoft το καταλαβε αυτο αρκετα νωρις και αφησε τα προιόντα της να πειρατευτουν μαζικα. Το πανηγυρι κρατησε πανω απο 25 χρονια. Και τωρα χανει γιατι καποιος αλλος εφτιαξε κατι αλλο και το δινει απο την αρχη και μαζικα δωρεαν.
Η Apple φαινομενικα λυσαει, αλλα ολα ειναι θεμα καποιων χρηματων. Ουτως η αλλως εχει ήδη βγαλει αρκετά.
Ο αυτοματισμος παντα θα ειναι συντηρητικος στην υιοθετηση νεων πραγματων σε αυτα τα επιπεδα. Ομως θα οδηγηθει εκει κυριως λογω κοστους..
Τελικα αυτο που μενει ειναι οι βασικες αρχες και η μεθοδολογια προσεγγισης. Ολα τα αλλα μετα απο λιγο καιρο εξελλισονται, οποτε αν δεν εισαι στις επαλξεις καταληγεις να ψαχνεσαι.
Απο την αλλη, οτι δεν εξελισσεται πεθαινει...
Νομιζω οτι ειναι ωρα για μια βουτια ομως. 
Burn baby, burn |
 |
|
|
pfys
New Member

Greece
105 Posts |
Posted - 06 August 2012 : 18:49:01
|
quote: Απο την αλλη, οτι δεν εξελισσεται πεθαινει...
ποσο αληθινό...
Διεργασίες (Processes) – Νήματα (Threads)
Οι πρώτοι μικρουπολογιστές είχαν μια Κεντρική Μονάδα Επεξεργασίας (CPU) με ικανότητα χειρισμού δεδομένων μήκους 8 bits και υποστήριζαν εξωτερική μνήμη έως 64ΚBytes. Εσωτερικά είχαν καταχωρητές (registers) στους οποίους «φόρτωναν» τα δεδομένα από την μνήμη και τον δείκτη προγράμματος (Instruction Pointer) που έδειχνε την επόμενη προς εκτέλεση εντολή. Οι εντολές ήταν ανάκληση/αποθήκευση δεδομένων στην μνήμη και αριθμητικές και λογικές πράξεις ανάμεσα σε δυαδικούς αριθμούς. Η πρόσθεση 2 αριθμών 16 bits (0..64535) γινόταν με πρόγραμμα. Υπήρχε η δυνατότητα άμεσης εξυπηρέτησης εξωτερικών διακοπών (interrupts).
Τα ψηφία που χρησιμοποιούμε στο δεκαδικό σύστημα είναι 10 από 0..9. Μόλις ξεπεράσουμε το 9 προσθέτουμε ένα άσσο στο αριστερό ψηφίο (στο 0 αν δεν υπάρχει). Στο δεκαεξαδικό τα ψηφία είναι 16 τα 0..9,A,B,C,D,E,F στο οκταδικό 8 τα 0..7 και στο δυαδικό μόλις 2 τα 0..1 (άγει / δεν άγει)
Εξου και η υπογραφή του Dipoli. There are only 10 types of people in the world: Those who understand binary, and those who don't.
Είναι προφανής η σχέση του αριθμού των δακτύλων μας με το αριθμητικό σύστημα που χρησιμοποιούμε.
Με την εκκίνηση της η ΚΜΕ έτρεχε το πρόγραμμα που υπήρχε γραμμένο στο BIOS. Αυτό το πρόγραμμα εκκίνησης, με την σειρά του έψαχνε για συσκευές (κασετόφωνο, floppy disk, hard disk, κάρτα δικτύου) από τις οποίες διάβαζε το υπόλοιπο πρόγραμμα που θα εκτελούσε συνήθως ένα πρωτόγονο λειτουργικό σύστημα.
Η μνήμη RAM ήταν κοινή για προγράμματα και δεδομένα και μόνο ένα πρόγραμμα μπορούσε να εκτελεσθεί κάθε φορά. Η οθόνη έδειχνε μόνο χαρακτήρες.
Οι σημερινοί μ/υ, εκτελούν μια αντίστοιχη διαδικασία εκκίνησης και το πρόγραμμα που φορτώνουν και αρχικά εκτελούν λέγεται λειτουργικό σύστημα. Το λειτουργικό σύστημα (windows, linux) διαχειρίζεται τους χρήστες με τα δικαιώματά τους, την χρήση της μνήμης και των περιφερειακών συσκευών και εμφανίζουν στην οθόνη τους ένα περιβάλλον εργασίας που προσομοιάζει την επιφάνεια του γραφείου μας.
Το λειτουργικό σύστημα (λ/σ) διαιρεί το χρόνο επεξεργασίας της ΚΜΕ σε φέτες (slices) και επιτρέπει την εκτέλεση πολλών εφαρμογές παράλληλα κατανέμοντας σε κάθε μία ίσο χρόνο εκτέλεσης. Το λ/σ δημιουργεί για κάθε εφαρμογή (processes) ένα ιδεατό περιβάλλον, απομονωμένο από τις άλλες εφαρμογές ή το ίδιο το λ/σ, επιτρέπει την πρόσβαση στις περιφερειακές συσκευές (κάθε εφαρμογή νομίζει ότι της ανήκει το ένα και μοναδικό mouse) και επιτρέπει την κοινή χρήση του κώδικα των ήδη φορτωμένων dlls.
Κάθε εφαρμογή ξεκινάει και συνήθως κατευθύνεται από τον χρήστη βάσει των επιλογών του menu. Δηλαδή κάθεται και περιμένει το χρήστη να κάνει μία επιλογή ή να εισάγει μία τιμή. Είναι πολλές φορές αναγκαίο να εκτελεσθούν και άλλες λειτουργίες παράλληλα (πχ να δέχεται απομακρυσμένες εντολές μέσω του δικτύου). Ένα νέο νήμα (thread) εκτέλεσης προγράμματος, μέσα στα όρια της εφαρμογής αλλά χωρίς την επιβάρυνση την δημιουργίας νέου process.
Κάθε εφαρμογή έχει ένα κύριο νήμα (main thread) εκτέλεσης που χειρίζεται την εμφάνιση της εφαρμογής (ενημέρωση παραθύρων κτλ). Αν, πιέζοντας ένα button, προκαλούμε ένα χρονοβόρο υπολογισμό τότε σε αυτό το διάστημα η οθόνη θα «παγώσει». Μπορούμε να δημιουργήσουμε ένα νέο νήμα που παράλληλα θα υπολογίσει το ζητούμενο χωρίς να μπλοκάρει την κυρίως εφαρμογή. Η ΚΜΕ εκτελεί κάθε φορά ένα thread. Με την έλευση των πολλαπλών πυρήνων ή των πολλαπλών ΚΜΕ το λ/σ μπορεί να προγραμματίσει την παράλληλη εκτέλεση των threads σε όλους του διαθέσιμους πυρήνες.
Συγχρονισμός.
Έστω ότι έχουμε δύο threads που πρέπει, το καθένα, να αυξήσει κατά 1 την τιμή μιας μεταβλητής. Η διαδικασία σε ψευτο-γλώσσα μηχανής είναι
move variable, accum,
Add accum,1
move accum, variable
Αν η πρώτη διαδικασία ξεκινήσει τότε η δεύτερη θα πρέπει να περιμένει έως ότου ενημερωθεί η μνήμη με την νέα τιμή. Η ΚΜΕ διακόπτει την εκτέλεση του 1ου thread μετά την πρώτη εντολή και προγραμματίζει για εκτέλεση το 2ο thread. Έτσι αντί να έχουμε τελική τιμή 2 θα έχουμε τιμή 1.
Χρειαζόμαστε σηματοδότες στους οποίους περιμένουμε στο κόκκινο και ξεκινάμε στο πράσινο.
Lock // ο σηματοδότης γίνεται κόκκινος
Load accum, variable // φώρτωσε την μεταβλητη στο καταχωρητή
Inc accum,1 // αυξησε την τιμή του καταχωρητή κατά 1
Save accum, variable // αποθήκευσε τον καταχωρητή στη μεταβλητή
Unlock // ο σηματοδότης γίνεται πράσινος
Η χρήση του σηματοδότη αναγκάζει όλες τις διαδικασίες να μπουν στην σειρά και εξασφαλίζει την σωστή πρόσβαση σε κοινά δεδομένα.
|
 |
|
|
pfys
New Member

Greece
105 Posts |
Posted - 12 August 2012 : 18:32:16
|
Threads συνέχεια
Για να ορίσουμε ένα νέο TMyThread κληρονομούμε την βασική κλάση TThread και αντικαθιστούμε (override) την μέθοδο execute.
Ενσωματώνουμε στην νέα κλάση αντικείμενα ή μεταβλητές που απαιτούνται. Το thread εκτελεί οτι ορίζει η ρουτίνα Execute. Όταν αυτή τελειώσει τότε τελειώνει και το thread.
Δημιουργούμε ένα TMyThread με την χρήση του constructor TMyThread. Create(CreateSuspended: Boolean). Συνήθως το δημιουργούμε ανενεργό TThread.Create(true), αρχικοποιούμε όσες μεταβλητές του ΤThread απαιτείται και στην συνέχεια καλούμε την μέθοδο Resume για να το ενεργοποιήσουμε.
TFileCopy = class(TThread)
private
FsrcFNames,
FdstFnames:TStrings;
protected
procedure Execute; override;
public
constructor CopyFiles(const srcFNames,dstFnames:TStrings);
procedure Stop;
end;
…
procedure TFileCopy.Execute;
...
begin
...
while not Terminated do
begin
// πως χρησιμοποιούμε το try/finally με πολλά objects
fsrc:=nil;
fdst:=nil;
try
…
// Ελέγχουμε πάντα τα exceptions γιατί διαφορετικά
// διακόπτεται η εκτέλεση του thread
try
// επικοινωνία με το κύρια φόρμα της εφαρμογής
PostMessage(UIHandle, COPY_EVENT, 1, fsrc.Size);
Except
// επικοινωνία με το κύρια φόρμα της εφαρμογής με strings
debug(Exception(ExceptObject).Message);
PostMessage(UIHandle, COPY_EVENT, 0, 0);
end;
finally
fdst.free;
fsrc.Free;
end;
end;
Διακοπή εκτέλεσης του thread
procedure TFileCopy.Stop;
begin
Terminate;
WaitFor;
end;
Επικοινωνία με το κύρια φόρμα της εφαρμογής με strings.
TMainFrm = class(TForm)
…
procedure LogEvent(var Msg: TMessage); message LOG_EVENT;
…
end;
procedure TMainFrm.LogEvent(var Msg: TMessage);
begin
Log(pchar(msg.wParam));
StrDispose(pchar(msg.wParam));
end;
procedure TMainFrm.FormCreate(Sender: TObject);
begin
....
UIHandle:=Handle;
end;
procedure Debug(const msg:string);
var p:pchar;
begin
if UIHandle=INVALID_HANDLE_VALUE then
outputdebugstring(pchar(msg))
else begin
p:=strNew(pchar(msg));
PostMessage(UIHandle,LOG_EVENT,integer(p),0)
end;
end;
Προσοχή στα strings ή σε reference counted μεταβλητές που είναι μέλη ενός record. Δεν μπορούμε να αρχικοποιήσουμε το record με την Fillchar. (βλέπε procedure Finalize)
Στο http://www.filefactory.com/file/6zopl4flpvdv/n/Example01.rar θα βρείτε το source & exe για το παραπάνω παράδειγμα.
|
 |
|
|
pfys
New Member

Greece
105 Posts |
Posted - 21 August 2012 : 04:15:12
|
Συνέχεια στα threads και εισαγωγή στα Sockets
Κάτι οι βουτιές στο τσουκαϊτι, κάτι τα τσίπουρα, κάτι η πολυπλοκότητα του θέματος καθυστέρησαν την πολυαναμενόμενη συνέχεια. Αλλά φευ, συνεχίζω ακάθεκτος.
Η πλήρης εκμετάλλευση των δυνατοτήτων των νέων Η/Υ, συνεπάγεται χρήση όλων των πυρήνων και τη δημιουργία εφαρμογών που εκτελούν τα υπολογιστικά τους καθήκοντα παράλληλα, μοιράζοντας τα σε μια ομάδα από διαθέσιμους εργάτες νήματα (working Threads). Το λειτουργικό σύστημα, αναθέτει την εκτέλεση των νημάτων στους υπάρχοντες πυρήνες (cores).
Θα σχεδιάσουμε μία εφαρμογή που θα μπορεί να «κατεβάσει» ένα ολόκληρο ιστότοπο (www.monachos.gr) σε τοπικό δίσκο. Θα ξεκινά με την πρώτη σελίδα (/forum/) και αφού την κατεβάσει, θα ψάξει για τις υπάρχουσες αναφορές της σε άλλες σελίδες (στο ίδιο ή άλλο ιστότοπο). Η διαδικασία θα είναι αναδρομική. Η ανάγνωση μίας σελίδας από ένα ιστότοπο (βασική λειτουργία του περιηγητή) απαιτεί χρήση Sockets και του πρωτοκόλλου HTTP 1.0/1.1
Sockets (υποδοχή)
Socket είναι μια υποδοχή που επιτρέπει την επικοινωνία ανάμεσα σε 2 Η/Υ (server & client) για την ανταλλαγή δεδομένων μέσω της δικτυακής υποδομής.
Στόχος είναι η δημιουργία, ανάμεσα σε δύο άκρα, ένα ιδεατού κυκλώματος ψηφιακής επικοινωνίας.
Το άκρο του πελάτη εκκινεί την σύνδεση, χρησιμοποιώντας μία υποδοχή πελάτη (client socket) την διεύθυνση και την θύρα του εξυπηρετητή. Ο εξυπηρετητής, μέσω μίας υποδοχής αναμονής (listening socket) υποδέχεται συνδέσεις. Κάθε αίτηση σύνδεσης, δημιουργεί το 2η άκρο, μία νέα υποδοχή εξυπηρετητή (server socket) αποκλειστικά για αυτή τη σύνδεση και συνήθως ένα νήμα που θα χειρισθεί την επικοινωνία των 2 άκρων.
http://www.inetdaemon.com/tutorials/internet/tcp/3-way_handshake.shtml
Εφαρμογή SiteGrab
Αν υποθέσουμε ότι έχουμε μια ομάδα από εργάτες νήματα και μία λίστα διαφόρων εργασιών. Ένας επιστάτης διατηρεί την λίστα εργασιών ενημερωμένη, ελέγχει την διαθεσιμότητα κάθε εργάτη νήμα και αναθέτει εκκρεμείς εργασίες σε ελεύθερους εργάτες νήματα έως ότου όλοι οι εργάτες νήματα είναι απασχολημένοι ή έχει αναθέσει όλες τις εργασίες προς εκτέλεση. Μόλις ο επιστάτης τελειώσει με την λίστα εργασιών «κοιμάται» (δεν καταναλώνει πόρους του Η/Υ) έως ότου ανατεθεί νέα εργασία. Ίσως, από κοινωνιολογική άποψη, μια σύγκριση με το αντίστοιχο ανθρώπινο μοντέλο εργασίας να μας οδηγούσε σε ενδιαφέροντα συμπεράσματα.
Η εφαρμογή δημιουργεί ένα object εργασία και το αναθέτει στον επιστάτη για να το υλοποιήσει.
Κλάση Εργασία Η κλάση εργασία (TBasicWorkObject) περιλαμβάνει όλα τα απαραίτητα δεδομένα και μία μέθοδο εκτέλεσης της. Ορίζεται σαν
TBasicWorkObject=class
public
procedure doWork; virtual; abstract;
end;
Η πραγματική εργασία TGrabUrl κληρονομεί απο την TBasicWorkObject και γνωρίζει να «κατεβάζει» μία σελίδα από ένα ιστότοπο.
TGrabUrl=class(TBasicWorkObject)
private
FClientSocket: TClientSocket;
..
public
procedure doWork; override;
constructor Create(const aSite,aUrl:string;aDepth:integer); overload;
..
property Stream:TMemoryStream read FStream;
property Depth:integer read FDepth;
end;
Η TGrabUrl.doWork κατεβάζει την σελίδα και ενημερώνει την κύρια φόρμα
postmessage(UIHandle,WORK_DONE,integer(self),0);
Εκεί γίνεται η επεξεργασία και η αποθήκευση της σελίδας.
Κάθε ιστότοπος έχει δενδρική δομή και κάθε επίπεδο χαρακτηρίζεται απο το βάθος του.
Κλάση Επιστάτης
Η κλάση επιστάτης, διατηρεί την λίστα εργασιών για κάθε σελίδα που πρέπει να κατεβάσει και δημιουργεί και ελέγχει τα νήματα εργάτες. Ξυπνάει περιοδικά, και αν υπάρχει εργασία και διαθέσιμο νήμα εργάτης την προγραμματίζει προς εκτέλεση.
TThreadsMngr=class(TThread)
private
FPeriod:integer;
FThreads,
FWorkQ :TObjectList;
...
public
constructor Create(WorkThreadClass:TWorkThreadClass;
DefThreadCount:integer=10);
...
procedure QueueWork(work:TBasicWorkObject);
end;
Εργάτες νήματα
Κάθε εργάτης νήμα «κοιμάται» και περιμένει 2 σηματοδότες (events) να ενεργοποιηθούν για να δουλέψει ή να τερματίσει. Εκτελεί την εργασία του, καλώντας την μέθοδο TBasicWorkObject.doWork και μόλις τελειώσει ξανακοιμάται.
TWorkThread=class(TThread)
private
FWorkObj : TBasicWorkObject;
...
public
constructor Create(aId:integer;aHandle:THandle);
procedure Work(aWorkObj:TBasicWorkObject);
...
end;
procedure TWorkThread.Work(aWorkObj:TBasicWorkObject);
begin
FWorkObj:=aWorkObj;
FWorkEvent.SetEvent;
if Suspended then Resume; // FWorkEvent will signal imediatelly
end;
procedure TWorkThread.Execute;
begin
H[0] := FStopEvent.Handle;
H[1] := FWorkEvent.Handle;
while not Terminated do
case WaitForMultipleObjects(2, @H, False, INFINITE) of
WAIT_OBJECT_0 : Terminate; // StopEvent Signaled
WAIT_OBJECT_0 + 1 : begin // WorkEvent Signaled
try
FWorkObj.doWork;
except
end;
FWorkEvent.ResetEvent; // Lower WorkEvent
end;
end
end;
Στο παράδειγμα υλοποίησα την ανάγνωση της πρώτης σελίδας /forum/ από τον ιστότοπο (www.monachos.gr ) και ανεύρεση όλων των αναφορών σε σελίδες (πχ http://www.monachos.gr/forum/topic.asp? TOPIC_ID=3931) 1ου επιπέδου που περιέχει .
Η αρχική σελίδα αποθηκεύεται σαν c:\temp\forum\default.htm
Μπορείτε να κατεβάσετε την εφαρμογή και το source από το example02.rar http://www.filefactory.com/file/1pjnx7y8tu2p/n/Example02_rar
There always be one more bug. |
 |
|
|
pfys
New Member

Greece
105 Posts |
Posted - 25 August 2012 : 21:09:01
|
TCP Sockets και modbus
H Borland, συγνώμη Embarcadero, σταμάτησε σιωπηλά την υποστήριξη στα socket components και στην θέση τους πρότεινε τα Open Source Indy components.
Αρχικά η επικοινωνία ενός client με ένα server υλοποιήθηκε σαν σύγχρονη. Ο πελάτης περίμενε (blocking) έως ότου πάρει απάντηση και δεν μπορούσε να κάνει κάτι άλλο. Για να εξυπηρετηθεί η επικοινωνία περισσοτέρων πελατών σε κάθε σύνδεση με το listening socket επικράτησε η χρήση ενός νήματος αποκλειστικά για την συγκεκριμένη επικοινωνία. Τα Indy υποστήριξαν το ασύγχρονο μοντέλο με το οποίο αποστέλλεται ειδοποίηση όταν η απάντηση είναι διαθέσιμη.
Η σύγχρονη (blocking) επικοινωνία (σειριακή ή δικτυακή) είναι πιο απλή και πιο εύκολη στη υλοποίηση.
Άλλες βιβλιοθήκες με υποστήριξη TCP/IP είναι http://synapse.ararat.cz/doku.php http://lnet.wordpress.com/
Κλάσεις για sockets
TCustomWinSocket (abstract)
| | |
TClientWinSocket TServerClientWinSocket TServerWinSocket
Υποδοχή πελάτη (client socket) : TClientWinSocket Υποδοχή αναμονής (listening socket) : TServerWinSocket Υποδοχή εξυπηρετητή (server socket): TServerClientWinSocket
Components (μπορούμε να ορίσουμε τιμές στις ιδιότητες τους μέσω του Object inspector). Χρησιμοποιούν το TCustomWinSocket
TAbstractSocket (abstract)
|
TCustomSocket (abstract)
| |
TClientSocket TCustomServerSocket (abstract)
|
TServerSocket
Χρησιμοποιώ την κλάση TWinSocketStream που μου παρουσιάζει την διαδικασία εγγραφή ή ανάγνωσης από socket σαν σε αρχείο.
ModBus
Είναι ένα πρωτόκολλο επικοινωνίας για βιομηχανικές συσκευές ελέγχου διαδικασιών και των συσκευών επιτήρησης τους. Επιτρέπει την μετάδοση της κατάστασης ψηφιακών/αναλογικών εισόδων (από τις συσκευές που τις συλλέγουν) και τον καθορισμό παραμέτρων αναφοράς από τους επιτηρητές.
http://www.prosoft-technology.com/kb/assets/intro_modbustcp.pdf http://www.modbus.org/tech.php
Η επικοινωνία απαιτεί 2 συσκευές (master-slave). Η master συσκευή εκκινεί την επικοινωνία και ρωτάει ή δίνει εντολές στον slave. Οι slave συσκευές απαντούν στα ερωτήματα που τους απευθύνει ο master.
Βασισμένη στα Indy componets, υπάρχει η ελεύθερη ModBusTCP βιβλιοθήκη (http://sourceforge.net/projects/delphimodbus/) που υλοποιούν το modbus σε TCP/IP.
Μια απλή εφαρμογή είναι η επιτήρηση της κατάστασης ενός slave PLC που με την σειρά του ελέγχει μια διαδικασία. Θα χρειασθούμε ένα modbus master που θα «μιλήσει» με function codes 3 με το PLC και θα διαβάσει ή θα γράψει σε μνήμες που αντιστοιχούν σε εισόδους (ψηφιακές ή αναλογικές) ή εξόδους. Για να υλοποιήσουμε μία master modbus εφαρμογή απαιτείται ένα απλό client socket. Μία slave modbus εφαρμογή είναι στην ουσία ένας πολυνηματικός tcp/ip server που ακούει στην θύρα 502 και αποδέχεται μηνύματα στην παρακάτω μορφή.
|Modbus Application Protocol (MBAP) Header | Protocol Data Unit (PDU)|
|------------------------------------------+-------------------------|
|Transaction |Protocol | Length | Unit | Function | Data |
|Identifier |Identifier| Field | ID | Code | |
|--------------------------------------------------------------------|
| (2 bytes) |(2 bytes) |(2 bytes)|(1 byte)|(1 byte) | Μεταβλητό |
|------------------------------------------+-------------------------|
Μπορείτε να κατεβάσετε την εφαρμογή και το source από το ModbusMaster.rar
http://www.filefactory.com/file/6skbkpq7x7rb/n/ModbusMaster_rar
Και για δοκιμές της επικοινωνίας υπάρχει ο Modbus PLC Simulator http://www.plcsimulator.org/

H τιμή $AA στην θέση 4001 +0 απεικονίζεται στα leds M100.0 .. M100.7 H float32 τιμή στην θέση 4001 +1 & 4001 +2 εμφανίζεται σαν θερμοκρασία. Τα 3 πρώτα bits στην θέση 4001+3 απεικονίζεται στα leds M106.0 .. M106.2
Οι έξοδοι προκαλούν αλλαγές στο high byte στην θέση 4001 +0.
There’s always one more bug. |
 |
|
|
pfys
New Member

Greece
105 Posts |
Posted - 28 August 2012 : 22:38:45
|
Modbus & big endian vs little endian
Έστω ότι έχουμε ένα 16 bit αριθμό 0x1234.
Πως αποθηκεύεται στην μνήμη του υπολογιστή ?.
Αν υποθέσουμε ότι η πρώτη θέση μνήμης έχει διεύθυνση 0, η επόμενη 1 κοκ τότε σε KME (CPU) της intel το νούμερο θα αποθηκευτεί σαν 34 12 (little endian) ενώ σε KME της Motorola (o εκπληκτικός 68000) το νούμερο θα αποθηκευτεί σαν 12 34 (big endian).
Προσομοιωτής. Εκπληκτικό εργαλείο, αρκεί να τηρείς τις αναλογίες με το πραγματικό κόσμο.
Το modbus χρησιμοποιεί big endian διάταξη των αριθμών στα διάφορά μυνήματά του.
Κατά συνέπεια αν θέλουμε να ελένξουμε στο πρόγραμμά μας την ύπαρξη alarm (bit 0) με μάσκα 0x0001 η τιμή που πρέπει να εισάγουμε στο simulator είναι 0100 και ΟΧΙ 0001.
Μικρές λεπτομέρειες ... |
 |
|
|
pfys
New Member

Greece
105 Posts |
Posted - 07 September 2012 : 18:04:37
|
TCP/IP Server Θα υλοποιήσω ένα απλό TCP/IP πολυνηματικό διακομιστή (Server) χρησιμοποιώντας τα TServerSocket & TClientSocket components. (Απαιτείται να εγκατασταθεί το package /bin/dclsockets70.bpl) Στο http://delphi.about.com/od/networking/l/aa112602a.htm θα βρείτε περισσότερες πληροφορίες για την χρήση των συγκεκριμένων components. Επίσης στο http://www.overbyte.be/frame_index.html?redirTo=/products/ics.html θα βρείτε μια διαφορετική υλοποίηση από Indy και Delphi socket components.
Για πελάτες (clients) θα χρησιμοποιήσουμε
1. Ένα απλό browser που θα «χτυπάει» μία http διεύθυνση
http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]] και στην περίπτωσή μας http://127.0.0.1:1024
H παραπάνω HTTP κλήση εμφανίζεται στον Server σαν το παρακάτω κείμενο
GET / HTTP/1.1
Host: 127.0.0.1:1024
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:15.0) Gecko/20100101 Firefox/15.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en,el;q=0.8,el-gr;q=0.5,en-us;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Connection: keep-alive
Ο Server απαντά
HTTP/1.1 200 OK
Content-Length: 11
Hello World
Connection: close
[empty line]

2. Το telnet στο οποίο θα επιστρέφεται ότι στέλνουμε (echo). Start/Run Cmd Στο Dos box πληκτρολογούμε telnet 127.0.0.1 1024 Πληκτρολογούμε «Hello» και το αποστέλλουμε στον Server με Enter
Client ---------- initate connection -----------> Server
...
Client <---------------command------------------- Server
Client ----------------response-----------------> Server
...
Client <---------------command------------------- Server
Client ----------------response-----------------> Server
Πρέπει να υλοποιηθεί το RFC 854, και δεν μπορεί να συνυπάρξει με το modbus ή το Web server

3. To modbus client. Θα πρέπει να επιλέξουμε για θύρα που ακούει ο Server την 502.
|Modbus Application Protocol (MBAP) Header | Protocol Data Unit (PDU)|
|------------------------------------------+-------------------------|
|Transaction |Protocol | Length | Unit | Function | Data |
|Identifier |Identifier| Field | ID | Code | |
|--------------------------------------------------------------------|
| (2 bytes) |(2 bytes) |(2 bytes)|(1 byte)|(1 byte) | Μεταβλητό |
|------------------------------------------+-------------------------|
Υλοποίησα, στον TCP/Server, ένα modbus client που υποστηρίζει μόνο τις παρακάτω functions.
03 (0x03) Read Holding Registers Βλέπε MODBUS Application Protocol Specification V1.1b σελίδα 19/51 http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf
06 (0x06) Write Single Register Βλέπε. MODBUS Application Protocol Specification V1.1b σελίδα

Statefull Ένας WebServer, δημιουργεί για κάθε νέα σύνδεση ένα SessionId που το επιστρέφει στον Client σαν Cookie. Με κλειδί αυτό το SessionId, ο WebServer, συσχετίζει όλη τα δεδομένα του συγκεκριμένου client (user name, db connection κτλ) Ο ίδιος client, στην επόμενη επικοινωνία του, αποστέλλει το SessionId ώστε να επαναχρησιμοποιήσει τα δεδομένα που όρισε σε προηγούμενη κλήση (statefull).
Περιγραφή του προγράμματος. Ο server ακούει στην πόρτα 1024 και για κάθε νέα σύνδεση πελάτη δημιουργεί ένα ξεχωριστό thread που θα χειρίζεται την επικοινωνία μεταξύ τους (ServerType= stThreadBlocking). Μόλις αποσταλεί η απάντηση στον πελάτη, το νήμα τελειώνει την εργασία του και επιστρέφει στο pool. Η επόμενη κλήση από τον ίδιο πελάτη δεν θα συσχετισθεί με καμία προηγούμενη (stateless). Δημιουργούνται νήματα (threads) κλάσης που κληρονομεί από την TServerClientThread και επιστρέφονται στο Server μέσω του event OnGetThread.
procedure TFrmServer.ServerGetThread(Sender: TObject; ClientSocket: TServerClientWinSocket; var SocketThread: TServerClientThread);
begin
SocketThread:=TSrvThread.Create(ClientSocket, Handle);
end;
TSrvThread=class(TServerClientThread)
private
fHandle:THandle;
...
protected
procedure ClientExecute; override;
public
constructor Create(aSocket:TServerClientWinSocket;
aHandle:THandle);
end;
Στην procedure TSrvThread.ClientExecute; διαβάζουμε το εισερχόμενο TCP/IP μήνυμα.
Η ρουτίνα RequestType το κατηγοριοποιεί σαν rtHTTP, rtText, rtModBus ή rtBinary και απαντάει ανάλογα.
Στο http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html περιγράφεται ότι η πρώτη γραμμή ορίζεται σαν
Request-Line = Method SP Request-URI SP HTTP-Version CRLF
Όπου Method = "OPTIONS" ; Section 9.2
| "GET" ; Section 9.3
| "HEAD" ; Section 9.4
| "POST" ; Section 9.5
| "PUT" ; Section 9.6
| "DELETE" ; Section 9.7
| "TRACE" ; Section 9.8
| "CONNECT" ; Section 9.9
| extension-method
extension-method = token
Στο πρόγραμμα κατηγοριοποιώ την κλήση σαν http αν περιέχει το HTTP/1. και ξεκινάει με τις λέξεις GET ή HEAD.
Ο χειρισμός του telnet, είναι διαφορετικός. To socket παραμένει «ανοικτό» έως να έρθει κάποιος control χαρακτήρας.
Το πρόγραμμα χρειάζεται επεκτάσεις εάν κάποιος θέλει να κάνει πραγματική δουλειά με αυτό.
Η πρώτη και σημαντικότερη είναι η υλοποίηση μιας κλάσης TModbus που θα υλοποιεί το modbus πρωτόκολλο έτσι ώστε ο κώδικας (C μεταφιεσμένη σε Pascal) να γίνει συντηρήσιμος.
rtModBus : begin
case pbFC^ of
$03 : begin // mbfReadHoldingRegs = $03;
pa:=pword(FRequest);
pd:=pa;
inc(pa, 4); // points to Start Address
inc(pd, 5); // point to count
move(FRequest^,data[0],8);
cnt:=swap(pd^);
data[ 8]:=cnt*2;
pd:=pword(@data[9]);
for i:=0 to pred(cnt) do begin
w:=SendMessage(fHandle,REG_GET,swap(pa^)+i,0);
pd^:=swap(w);
inc(pd);
end;
size:=8+1+cnt*2;
data[5]:=2 + 1 + cnt*2;
ClientSocket.SendBuf(data,size);
end;
Μπορείτε να κατεβάσετε την εφαρμογή και το source από το http://www.filefactory.com/file/dftvw1w1xw7/n/Server01_rar
Και παραφράζοντας τον μαύρο πειρατή (Αστερίξ στη Κορσική σελ. 19) Bugus humanum est
Καλό φθινόπωρο |
 |
|
|
pfys
New Member

Greece
105 Posts |
Posted - 09 September 2012 : 15:41:35
|
Σωστή ή λανθασμένη υλοποίηση ;
Μετά από αρκετά χρόνια στην δουλειά βλέπω το λάθος από μακριά. Και από μια παράξενη σύμπτωση όταν ελέγχω την δουλειά κάποιου άλλου σχεδόν πάντα «σκοντάφτω» επάνω του.
Σαν να είναι εκεί και να μου κλείνει το μάτι και να μου λέει «προσπέρνα με».
Στην υλοποίηση του Server έμπλεξα τις λειτουργίες του server με τον χειρισμό των μηνυμάτων. Ο Server διαχειρίζεται tcp/ip συνδέσεις, και «περνάει» τα μηνύματα σε κατάλληλους χειριστές (handler threads). Εκεί τα πράγματα πρέπει να είναι επίσης καθαρά και την αποκωδικοποίηση της ερώτησης και την κωδικοποίηση της απάντησης πρέπει να την κάνει μια άλλη HTTP ή Telnet ή TModbus κλάση.
Η απάντηση λοιπόν είναι απλή. Ξαναγράψτο. Νέα σχεδίαση, υλοποίηση και τεκμηρίωση.
TModbus Το modbus είναι ένα πρωτόκολλο ανταλλαγής ερωτήσεων & απαντήσεων και παρέχει μία client/server επικοινωνία μεταξύ συσκευών συνδεδεμένων μέσω TCP/IP. Κάθε ερώτημα περιγράφεται από ένα κωδικό (function code FC). Το modbus πρωτόκολλο απεικονίζει τις διευθύνσεις και τα δεδομένα με το πιο σημαντικό byte πρώτο (big Endian). Οι 4 κύριοι πίνακες που χρησιμοποιεί το Modbus είναι Διακριτές είσοδοι, απεικονίζονται σε bits και μπορούμε μόνο να τις διαβάσουμε. Coils, (solid-state relay) απεικονίζονται σε bits και μπορούμε να τις διαβάσουμε & να γράψουμε Input Registers, απεικονίζονται σε 16-bit word, μπορούμε μόνο να τις διαβάσουμε. Holding Registers, απεικονίζονται σε 16-bit word, μπορούμε να τις διαβάσουμε & να γράψουμε Οι βασικές λειτουργίες είναι (0x01) Read Coils (0x02) Read Discrete Inputs (0x03) Read Holding Registers (0x04) Read Input Registers (0x05) Write Single Coil (0x06) Write Single Register
O modbus Master ρωτάει ή καθορίζει τιμές για εισόδους ή εξόδους ενός PLC. To PCL είναι slave και απαντάει στα ερωτήματα του Master. Στην δική μας περίπτωση υλοποιούμε αμφοτέρους.
Ο Master/client χρησιμοποιεί ένα socket component για την TCP/IP σύνδεση με τον Server/ Slave. Κατασκευάζει ένα object της κλάσης TModbus και καλεί τις ρουτίνες που υλοποιούν τις βασικές λειτουργίες.
Τα αποτελέσματα εμφανίζονται σε array properties.
Modbus:=TModbus.Create(FSocket);
If Modbus.ReadHoldingRegisters(1,1) then
Modbus.HoldingRegs[1] έχει την ζητούμενη τιμή.
Ο Server/Slave έχει ήδη λάβει το TCP/IP μήνυμα και πρέπει να αποφασίσει τον τύπο του. Χρησιμοποιώντας τον 2ο constructor δημιουργεί ένα object και ελέγχει την ορθότητα του μηνύματος. Σε περίπτωση λάθους στην δομή του μηνύματος, δημιουργεί exception.
Η κλάση TModbus περικλείει (encapsulates) την δομή ενός modbus μηνύματος και ο παρακάτω κώδικας (ισάξιος μόνο για τον Chuck http://blog.magicsoftware.com/2011/09/if-chuck-norris-were-programmer.html )
// check for ModBus request
if FReqSize>=12 then begin
pwTI :=pword(p); // 0..1 Transaction Identifier
pwPI :=pword(p+2); // 2..3 Protocol Identifier
pwlf :=pword(p+4); // 4..5 Length Field
pbUID:=pbyte(p+6); // 6 Unit ID
// MB_IGNORE_UNITID = 255
pbFC :=pbyte(p+7); // 7; Function Code
// mbfReadHoldingRegs = $03;
// mbfWriteOneReg = $06;
// 8; Data
if ((pbFC^=$06) or (pbFC^=$03)) and (pwlf^=swap($0006)) then begin
result:=rtModBus;
exit;
end;
end; αντικαθίσταται με
try
FModbus:=TModbus.Create(FRequest^,FReqSize);
FModbus.OnGetData:=ModbusGetData;
FModbus.OnSetData:=ModbusSetData;
result:=rtModBus;
exit;
except
Log('Not modbus message');
end; Και ο επίσης «ανδρικός» κώδικας
rtModBus : begin
case pbFC^ of
$03 : begin // mbfReadHoldingRegs = $03;
pa:=pword(FRequest);
pd:=pa;
inc(pa, 4); // points to Start Address
inc(pd, 5); // point to count
move(FRequest^,data[0],8);
cnt:=swap(pd^);
data[ 8]:=cnt*2;
pd:=pword(@data[9]);
for i:=0 to pred(cnt) do begin
w:=SendMessage(fHandle,REG_GET,swap(pa^)+i,0);
pd^:=swap(w);
inc(pd);
end;
size:=8+1+cnt*2;
data[5]:=2 + 1 + cnt*2;
ClientSocket.SendBuf(data,size);
end; αντικαθίσταται με
rtModBus : begin
FModbus.PrepareResponse;
FModbus.Respond(ClientSocket);
FreeAndNil(FModbus);
end και η κλάση ΤModbus ακολουθεί.
TBytes = array of byte;
TMBAP = packed record { 7 bytes }
TrnId : word;
ProtocolIdent: word;
Len:word;
UnitId:byte;
end;
TPDU = packed record { 253 bytes }
FC : byte;
Data: packed record case integer of
0 : (b: array[0..251] of byte);
1 : (w: array[0..125] of word);
2 : (o: packed record
len : byte;
w : array[0..124] of word;
b : byte;
end)
end;
end;
TADU = packed record // 260 bytes
MBAP : TMBAP;
PDU : TPDU;
end;
|Modbus Application Protocol (MBAP) Header | Protocol Data Unit (PDU)|
|------------------------------------------+-------------------------|
|Transaction |Protocol | Length | Unit | Function | Data |
|Identifier |Identifier| Field | ID | Code | |
|--------------------------------------------------------------------|
| (2 bytes) |(2 bytes) |(2 bytes)|(1 byte)|(1 byte) | Μεταβλητό |
|------------------------------------------+-------------------------|
TModbus = class
Private
...
Public
// Client Side
constructor Create(aSocket:TCustomWinSocket); overload;
// Server Side
constructor Create(const Request; size:word); overload;
procedure PrepareResponse;
procedure Respond(aSocket:TCustomWinSocket);
function ReadCoils(StartAddress, Count:word):boolean;
function ReadDiscreteInputs(StartAdd,Count:word):boolean;
function ReadHoldingRegisters(RegNo,Count:word):boolean;
function ReadInputRegisters(RegNo,Count:word):boolean;
procedure WriteSingleCoil(Addr:word;value:boolean);
procedure WriteSingleRegister(RegNo,value:word);
property DiscreteInput[idx:integer]:boolean read ...
property Coils[idx:integer]:boolean read ...
property InputRegs[idx:integer]:word read ...
property HoldingRegs[idx:integer]:word read ...
property FC:byte read FFC;
property Request:TBytes read GetRequest;
property Response:TBytes read GetResponse;
property OnGetData:TOnExchangeData read ...
property OnSetData:TOnExchangeData read ...
end; Νομίζω ότι πλέον γίνεται φανερή η χρησιμότητα των objects. Περιλαμβάνουν δεδομένα και μεθόδους που υλοποιούν τις υπηρεσίες τους προς τον χρήστη.
Έπρεπε, η κλάση TModbus να ανοίγει και την TCP/IP σύνδεση ? Αποφάσισα ότι η κλάση θα χρησιμοποιεί connected sockets και θα συνδιαλέγεται με την υπόλοιπη εφαρμογή με καθαρό τρόπο.
Επιπλέον η μνήμη που γράφει ή διαβάζει ο Server/Slave θα ανήκε στον ίδιο, και την διαχειρίζεται, την εμφανίζει ή στην κλάση TModbus που βασικά χερίζεται μόνο τον σχηματισμό των μηνυμάτων. Επέλεξα η μνήμη να ανήκει στον Slave και να η TModbus κλάση να επικοινωνεί με event Handlers
TOnExchangeData = procedure(FC:byte; param1,param2:word;var value:word) of object; Μπορείτε να κατεβάσετε την εφαρμογή και το source από το http://www.filefactory.com/file/vjru517ir15/n/Server02.rar
Παρατηρήσεις και σχόλια πάντα δεκτά.
|
 |
|
|
pfys
New Member

Greece
105 Posts |
Posted - 05 October 2012 : 00:59:57
|
Σειριακή επικοινωνία
Όταν χρησιμοποιήσαμε PSTN γραμμή συνδέαμε το modem στην σειριακή του υπολογιστή και «βγαίναμε» στο internet. Η σειριακή (RS232) επικοινωνία ήταν κυρίαρχη ανάμεσα σε συσκευές που είχαν να ανταλλάξουν δεδομένα. Σήμερα αντικαθίσταται σταδιακά με το USB των 480 kbits. Οι 2 σειριακές συσκευές ανταλλάσουν στοιχεία όταν η μία τα ζητήσει από την 2η ή όταν η 2η τα έχει έτοιμα και τα στέλνει χωρίς ερώτηση. Συνήθως οι διάλογοι είναι ερώτηση – απάντηση. Η σειριακή επικοινωνία βασίζεται σε ένα ηλεκτρικό και σε ένα λογικό πρωτόκολλο. Παλμοί στο καλώδιο Πώς θα κωδικοποιήσουμε την πληροφορία ενός byte σε ένα καλώδιο?. Στην σειριακή επικοινωνία δημιουργούμε μια παλμοσειρά σταθερής διάρκειας , με παλμούς για κάθε bit=1 του byte. Προστέθηκαν και κάποιοι επιπλέον παλμοί συγχρονισμού και ανίχνευσης σφάλματος επικοινωνίας και μεταδίδονται στο καλώδιο με συγκεκριμένη ταχύτητα. Χρησιμοποιούμε ένα οποιοδήποτε UART (πχ 8051) με ένα καλώδιο αποστολής (Tx) και ένα καλώδιο λήψης. http://www.slideshare.net/pantechsolutions/8051-serial-communicationuart Προφανώς, για λόγους συγχρονισμού οι 2 άκρες πρέπει να ρυθμισθούν στα ίδια χαρακτηριστικά σειριακής επικοινωνίας (ταχύτητα, parity, stop bits).
Ανίχνευση λαθών. Κάθε byte περιέχει άρτιο ή περιττό αριθμό από 1. Προσθέτοντας ένα ακόμα bit (παλμό) μπορείς να εξασφαλίσεις ότι ο αριθμός των 1 στο συγκεκριμένο byte είναι άρτιος ή περιττός (parity odd / even). Η ανίχνευση λαθών βασίστηκε στο μέτρημα των 1 κατά την λήψη και την επιβεβαίωση της συμφωνίας επικοινωνίας (odd/even parity). Το UART παράγει interrupts όταν ο καταχωρητής αποστολής (transmit register) είναι άδειος και ο καταχωρητής λήψης (receive register) γεμάτος. Αυτά τα interrupts φτάνουν στον driver του σειριακού που τα προωθεί σαν events στις εφαρμογές. Έτσι μπορούμε ασύγχρονα να ενημερωθούμε για την λήψη μέσω σειριακής επικοινωνίας ενός χαρακτήρα ή να γράψουμε σε ένα buffer το προς αποστολή μήνυμα και αφήσουμε να αποσταλεί . Όλα αυτά είναι μέρος του λειτουργικού συστήματος και αποτελούν πρόβλημα των οδηγών (drivers) των σειριακών θυρών. Τελικά έχουμε 2 συσκευές συνδεδεμένες με τουλάχιστον 3 καλώδια (Tx, Rx, Gnd) όπου το Tx της μίας συσκευής συνδέεται στο Rx της άλλης και έχουν κοινό Gnd.
Λογικό πρωτόκολλο. Ας δούμε ένα πρωτόκολλο επικοινωνίας για φορολογικούς εκτυπωτές (από αυτούς εκδίδονται οι αποδείξεις στα super market). ftp://ftp.accordgroup.ro/Pentru%20dealeri/Ithaki/PTR%20Dezvoltatori%20de%20Aplicatii/MICRELEC%20ETR%20EL%20JOURNAL%20PROTOCOL.pdf
Κάθε μήνυμα ξεκινά με τον STX (0x02) και τελειώνει με ΕΤΧ (0x03).
+-----+---------------+-----+
| STX | Data | ETX |
+-----+---------------+-----+
Όλα τα δεδομένα στα Data είναι ascii χαρακτήρες από 0x32 έως 0xFF.
Tx data packet
<--------------------- Data -------------------><--Checksum -->
+---------+---------+---------+------+---------+---------------+
| Request / Field 1 / Field 2 / .... / Field N / CC |
+---------+---------+---------+------+---------+---------------+
Request 1 char
Rx data packet
<--------------------- Data -----------------------------><-Checksum->
+---------+--------+--------+-------+-------+------------+-----------+
|Response /Status 1/Status 2/Field 1/Field 2/..../Field N/ CC |
+---------+--------+--------+-------+-------+------------+-----------+
Response,status1, status2 2 numeric digits
BYTE CalcChecksum(BYTE *packet)
{
BYTE sum = 0;
int checklength = strlen(packet) - 2;
while(check length--) sum += (BYTE) (*packet++);
return (sum % 100));
}
Σχεδίαση
1. Κάθε μήνυμα απαντάται σύμφωνα με την παρακάτω ροή
Sender (host) Receiver (device)
---------------------------------------------------------
IDLE IDLE
ENQUIRE --------------------->
<--------------------- ACKNOWLEDGE
Τx PACKET --------------------->
<--------------------- ACKNOWLEDGE
<--------------------- Rx PACKET
ACKNOWLEDGE --------------------->
IDLE IDLE
2. Όλα τα μηνύματα αποστολής μορφοποιούνται, πριν αποσταλούν, σε μία ρουτίνα 3. Όλα τα μηνύματα λαμβάνονται από μία ρουτίνα. 4. Χρησιμοποιώ blocking διαδικασία επικοινωνίας.
Η διαδικασία επικοινωνίας περιγράφεται από το παρακάτω διάγραμμα αλλαγής κατάστασης (state transition diagram).
|
 |
|
|
pfys
New Member

Greece
105 Posts |
Posted - 05 October 2012 : 01:17:35
|
και το διάγραμμα.

Η υλοποίηση ακολουθεί σε επόμενο post. |
 |
|
|
pfys
New Member

Greece
105 Posts |
Posted - 09 October 2012 : 17:23:34
|
Υλοποίηση
Σε όλα τα πρωτόκολλα επικοινωνίας υπάρχει ένα μήνυμα αποστολής και ένα μήνυμα απάντησης και πάντα θα υπάρχουν προβλήματα επικοινωνίας. Η υλοποίηση ενός πρωτοκόλλου πρέπει, απαραίτητα, να λαμβάνει υπόψιν τα σφάλματα (επικοινωνίας ή λογικά) και να χειρίζεται ανάλογα. Κρινόμαστε πρώτα από την λειτουργικότητα και έπειτα από την αξιοπιστία κάθε συστήματος. Από επικοινωνίες με σειριακούς φορολογικούς εκτυπωτές έως τις ανεμογεννήτριες.
TPacket Ας ξεκινήσουμε με την πρώτη κλάση που υλοποιεί την λειτουργικότητα του πακέτου αποστολής & λήψης.
TPacketType = (ptTx, ptRx);
TPacket = class(TObject)
...
public
constructor Create; overload;
constructor Create(aReq:char); overload;
destructor destroy; override;
class function CalcCheckSum(const data: string): string;
class function ChecksumValid(const data:string):boolean;
property Fields[index:integer]:string read GetField write SetField;
property Data:string read GetData write SetData;
property PacketType:TPacketType read fPacketType write fPacketType;
property RxResposeCode:integer read fRxResposeCode;
property RxStatus1:integer read fRxStatus1;
property RxStatus2:integer read fRxStatus2;
end; Όταν θέλουμε να δημιουργήσουμε ένα μήνυμα για αποστολή τότε
tx:=TPacket.Create('b'); // Request = SetVatRates
for i:=1 to 5 do // προσθέτουμε 5 συντελεστές ΦΠΑ
tx.Fields[i]:=format('%.2f/',[VatRates[i]]); Χρησιμοποιούμε το property data που προσθέτει και checksum
Όταν λαμβάνουμε ένα μήνυμα
rx:=TPacket.Create;
rx.data:=msg; // χωρίς STX, ETX τo property RxResposeCode:integer περιέχει την κωδικό επιτυχίας/αποτυχίας. Το array property fields τα πεδία του μηνύματος.
Χρησιμοποίησα για πρώτη φορά class functions. Χρειαζόμουν μία υπηρεσία (θα μπορούσα να είναι μια απλή βοηθητική function) που ανήκε σε μία κλάση και δεν ήθελα να δημιουργήσω object.
Η κλάση είναι ένα συμβόλαιο που απαριθμεί και περιγράφει υπηρεσίες. Για να "πάρουμε" αυτές τις υπηρεσίες δημιουργούμε objects μέσω του constructor κάθε κλάσης. Τα objects καταλαμβάνουν μνήμη για τις εσωτερικές μεταβλητές τους και όλα μοιράζονται τον κώδικα functions.
Η ίδια η κλάση μπορεί να μας δώσει υπηρεσίες αρκεί να μην χρησιμοποιεί μνήμη του object. O constructor, που δημιουργεί objects αποτελεί ΤΗΝ class function.
TSession Ακολουθεί η κλάση της επικοινωνίας. Εδώ υλοποιήσαμε την λογική του διαγράμματος αλλαγής καταστάσεων. Μελετήστε το και καταλάβετέ το. Ο κώδικας είναι πιστή αντιγραφή του.
TSession = class
...
public
constructor Create(const params:string); // COM1,9600,N,8,1
destructor destroy; override;
// <0 Σφάλμα επικοινωνίας
// 0 Επιτυχία επικοινωνίας & εκτέλεσης της εντολής
// >0 Σφάλμα πρωτοκόλλου
function Communicate(const TxPacket:TPacket;
out RxPacket:TPacket):integer;
end;

TFiscalPrinter Και καταλήγουμε στην κλάση που χρησιμοποιεί η εφαρμογή. Αυτή με την σειρά της χρησιμοποιεί την TSession & την Tpacket για την επικοινωνία με τον εκτυπωτή.
Αλλά οι υπηρεσίες που παρέχει είναι υψηλού επιπέδου, που μπορούν άμεσα να χρησιμοποιηθούν από μία εφαρμογή (application).
TFiscalPrinter = class
.. .
public
constructor create(const COMPort:string);
destructor destroy; override;
function FiscalTime:TDateTime;
function SerialNumber:String;
function TicketNumber:integer;
function ZNumber:integer;
procedure OpenDay; // Logical operation
procedure CloseDay; // Issue Z, read EJ
procedure OpenTicket(tt:TTicketType; const Title:string ='';
const Seira:string=''; number:integer=0);
procedure SaleItem(const code, descr, barcode:string;
price, quant, amount:double; vatCat:integer);
procedure VoidItem(const code, descr, barcode:string;
price, quant, amount:double; vatCat:integer);
procedure RefoundItem(const code, descr, barcode:string;
price, quant, amount:double; vatCat:integer);
procedure DiscountItem(const code, descr, barcode:string;
amount:double; vatCat:integer);
procedure SubTotalTicket;
procedure SubTotalDiscount(amount:double);
procedure CancelTicket;
procedure CloseTicket;
...
property capEJ:boolean read FcapEJ; // capability has Electronic Journal
property capSlip:boolean read FcapSlip;// capability has SlipPrinter
property Header[index:integer]:string read GetHeader write SetHeader;
property Footer[index:integer]:string read GetFooter write SetFooter;
property VatRates[index:integer]:string read GetVatRate write SetVatRate;
end;
ΥΓ. 1. Η μόνη μου παρατήρηση στο συγκεκριμένο πρωτόκολλο ήταν η λανθασμένη επιλογή του ‘/’ σαν διαχωριστή πεδίων (field separator) διότι μπορεί να υπάρξει και στα δεδομένα ενός πεδίου του μηνύματος. Θα μπορούσε να χρησιμοποιηθεί ο χαρακτήρας FS = 28 ή 0x 1C
2. Χρησιμοποιώ το async32 component. (open source) http://www.general-files.com/download/source/gs554ee144h32i0
3. Με αυτό το post τελείωσα με όσα θέματα είχα σκεφθεί να αναλύσω. Αναμένω προτάσεις και ερωτήσεις.
ΠΦ |
 |
|
|
Pirate
Advanced Member
    
Greece
3177 Posts |
Posted - 09 October 2012 : 22:32:47
|
Τι να πω! Μένω άφωνος! Πιστεύω ότι τόση ανάπτυξη κώδικα δεν πρέπει να υπάρχει σε άλλο forum ακόμη και του εξωτερικού. Η δουλειά αυτή Πάνο προορίζεται για τους επόμενους αναγνώστες του forum αυτού που αφενός θα είναι ειδικοί για να μπορέσουν να παρακολουθήσουν όλο αυτό το ξεδίπλωμα και αφετέρου πολύ ειδικοί θα έλεγα!
Εγώ δεν έχω να παρατηρήσω τίποτα διότι δεν έχω ασχοληθεί με modbus και επικοινωνίες γενικώς. Αν χρειασθεί να ασχοληθώ ξέρω αμέσως που θα ανατρέξω μιας και το έχω ήδη αρχειοθετήσει σε 23 σελίδες του acrobat. Το μόνο που θα πω είναι ότι αυτή η καταπληκτική γλώσσα (Pascal) που την πεθάνανε οι πεθαμεναντζήδες πάντα με συγκινεί!! Ακόμα και όταν την γράφει άλλος και όχι εγώ!
Υ.Σ. Μη περιμένεις «λαοθάλασσα» να σε ρωτάει και συ να απαντάς. Χτύπησες με την μία πολύ ψηλά τόσο ψηλά που θα πάσχεις από «μοναξιά». Έχε το υπ' όψη σου αυτό. Και πάλι εύγε!
Στίγμα Μαστροκαπετάνιου |
 |
|
|
pfys
New Member

Greece
105 Posts |
Posted - 09 October 2012 : 23:45:40
|
Καπετάνιε,
Από την αρχή σκόπευα στους νέους μηχανικούς. Αυτούς που στο πολυτεχνείο διδάχθηκαν να λύνουν προβλήματα. Σε αυτούς που τα μαθηματικά ήταν εργαλείο και όχι αυτοσκοπός. Μάθαμε και μαθαίνουνε να λύνουν προβλήματα αναλυτικά (σπάζοντάς τα σε μικρότερα κομμάτια) και συνδυαστικά (να ενώνουν μικρά κομμάτια γνωστής συμπεριφοράς και να δημιουργούν μεγαλύτερα).
Αλλά το λογισμικό, όσο soft και να είναι, απαιτεί σχεδίαση πριν την υλοποίηση. Αυτό προσπάθησα να τονίσω. Και πλέον οι κλάσεις και τα objects αποτελούν εργαλεία για να γράφουμε καλύτερο λογισμικό.
quote: πολύ ειδικοί θα έλεγα!
Δεν συμφωνώ για το πολύ ειδικοί. Αν οι μηχανολόγοι και οι ηλεκτρολόγοι πρέπει να γνωρίζουν τους τρόπους μετάδοσης της θερμότητας τότε θα πρέπει να γνωρίζουν να γράφουν και σωστά λογισμικό. Οι μηχανικοί φτιάχνουν συστήματα και όχι οι προγραμματιστές. Η γλώσσα προγραμματισμού αλλάζει αλλά όπως είπε και ο Σωτήρης
quote: Οι τεχνικες παραμενουν τεχνικες..
Εσύ ήσουν ήδη έτοιμος. Η περιέργειά σου σε είχε ήδη οδηγήσει στο να εξερευνήσεις τον αντικειμενοστρεφή προγραμματισμό. Αλλά να αλλάξεις αυτή την τεράστια unit με τις βοηθητικές functions που ξέρεις πια απέξω είναι δύσκολο.
Που ξέρεις, μπορεί τελικά και να προσελκύσω νέα μέλη μόνο για το λογισμικό. Αυτοί φυσικά θα μετράνε στους Ηλεκτρολόγους.
Θα συνεχίσω να γράφω για διάφορα θέματα που θα επιλέγω με το ίδιο, χαλαρό, ρυθμό.
Δάσκαλε, σε ευχαριστώ θερμά. Πάνος |
 |
|
| |
Topic  |
|
|
|
| ΘΕΡΜΑΝΣΗ - ΚΛΙΜΑΤΙΣΜΟΣ - ΜΗΧΑΝΟΛΟΓΙΚΑ |
© 2000 monachos |
 |
|
|