I/O Fahrpultsoftware für C++

Da immer mehr Zusi User von einem 1:1 Führerstand mit träumen, soll es zumindest an Datenaustausch nicht hapern.
Antworten
Nachricht
Autor
Andreas K.
Beiträge: 82
Registriert: 22.01.2007 18:01:17
Wohnort: Nürnberg

I/O Fahrpultsoftware für C++

#1 Beitrag von Andreas K. »

Nachdem ich meinen Schwager ein bisschen beschwatzt habe, werden wir eine I/O Karte selbst aufbauen. :D
Grundlage ist einen PIC18F2550 samt Ansteuerung über USB.

Hardwareseitig wird es keine Probleme geben. Er ist Elektronik/Mechatronic Ing. :hat3

Softwareseitig sieht es schon magerer aus ;(

Deshalb der Aufruf, ob jemand uns den Quellcode von einer Fahrpultsoftware für C++ geben kann. Weil gerade das Einbinden des TCP-Protokoll doch Probleme für uns darstellt.

Grüsse Andreas (der wohl wieder Haare beim Löten lassen muss, weil alles was größer als 0805 ist, nicht auf die Platine kommt :rolleyes: )
Zuletzt geändert von Andreas K. am 17.02.2010 22:05:51, insgesamt 1-mal geändert.

Andreas Karg
Beiträge: 4718
Registriert: 28.04.2002 12:56:00
Kontaktdaten:

Re: I/O Fahrpultsoftware für C++

#2 Beitrag von Andreas Karg »

In C# habe ich vor einiger Zeit eine (meiner Meinung nach) recht handliche Bibliothek geschrieben. Ich bin mir nicht sicher, ob man solche DLLs auch in C++ irgendwie einbinden kann. Müsste aber doch eigentlich gehen - Roland Ziegler weiß doch da bestimmt Bescheid.

protonmw (Marc)
Beiträge: 300
Registriert: 06.05.2009 10:59:49
Wohnort: Freiberg(Sachs)

Re: I/O Fahrpultsoftware für C++

#3 Beitrag von protonmw (Marc) »

Verdammt!! Sowas hatte ich doch auch vor! :P

Ich experimentiere z.Z in C++ und MFC mit einer Fahrpultansteuerung auf Basis der Konkurrenz (Atmel).
Allerdings kann ich mich erst nach diesem Wochenende intensiver damit befassen.

PS: Ich glaube nicht, dass das mit dem C# geht, da C# managed Code ist (also so ne art Interpretersprache so ähnlich wie bei Java). Zudem ist C# dadurch ca. 10mal langsamer als C++ ...
Zuletzt geändert von protonmw (Marc) am 18.02.2010 14:19:47, insgesamt 2-mal geändert.
MfG Marc

"Wir genießen das Leben in vollen Zügen!"

Andreas K.
Beiträge: 82
Registriert: 22.01.2007 18:01:17
Wohnort: Nürnberg

Re: I/O Fahrpultsoftware für C++

#4 Beitrag von Andreas K. »

@ protonmw:

Dann lass Dich dabei mal nicht stören! :D

Uns würde ja nur der allgemeine Teil interessieren.

Also:

Anmelden am TCP Server
Anfrage der Daten
Empfangen der Daten
etc.

Das Einbinden der notwendigen DLL wird sich ja immer unterscheiden.
Von Karte zu Karte.

Schreibst Du die USB Routine selber oder greifst Du auf eine fertige zurück?
Und sprichst Du die Karte über DLL oder einen virtuellen Port?

MfG Andreas

protonmw (Marc)
Beiträge: 300
Registriert: 06.05.2009 10:59:49
Wohnort: Freiberg(Sachs)

Re: I/O Fahrpultsoftware für C++

#5 Beitrag von protonmw (Marc) »

Nix mit USB!

Ich wollte mit der Leuchtmelderzeile beginnen, wo z.B. PZB, Sifa und Türen angezeigt werden. Dazu (versuche) ich die entsprechenden Daten aus Zusi zu lesen (via TCP Server). Die Daten sollen dann über die RS232 ausgegeben werden. Warum RS232? Nun, die ist zwar alt aber einfach!

Als Hardware ist ein RS485 Bus gedacht, an dem dann ATtiny2313'er dran hängen und die LEDs ansteuern. Später dann auch Servos für den Tacho, die Luft usw...

MfG Marc
MfG Marc

"Wir genießen das Leben in vollen Zügen!"

Andreas K.
Beiträge: 82
Registriert: 22.01.2007 18:01:17
Wohnort: Nürnberg

Re: I/O Fahrpultsoftware für C++

#6 Beitrag von Andreas K. »

Das kommt mir bekannt vor.

Ansteuerung von:

Leuchtmelder
PWM für Tacho
Servo oder Schrittmotoren für Manometer

Wir werden aber über USB gehen.
Aber nach der Dokumentation kann man das Board über einen virtuell Port als RS232 ansteuern.

MfG Andreas

protonmw (Marc)
Beiträge: 300
Registriert: 06.05.2009 10:59:49
Wohnort: Freiberg(Sachs)

Re: I/O Fahrpultsoftware für C++

#7 Beitrag von protonmw (Marc) »

Andreas K. hat geschrieben:Aber nach der Dokumentation kann man das Board über einen virtuell Port als RS232 ansteuern.
AHA!! :D
MfG Marc

"Wir genießen das Leben in vollen Zügen!"

Andreas K.
Beiträge: 82
Registriert: 22.01.2007 18:01:17
Wohnort: Nürnberg

Re: I/O Fahrpultsoftware für C++

#8 Beitrag von Andreas K. »

Mein Schwager kann auch Atmel brennen :mua

Benutzeravatar
Roland Ziegler
Beiträge: 5508
Registriert: 04.11.2001 22:09:26
Wohnort: 32U 0294406 5629020
Kontaktdaten:

Re: I/O Fahrpultsoftware für C++

#9 Beitrag von Roland Ziegler »

Andreas Karg hat geschrieben:In C# habe ich vor einiger Zeit eine (meiner Meinung nach) recht handliche Bibliothek geschrieben. Ich bin mir nicht sicher, ob man solche DLLs auch in C++ irgendwie einbinden kann. Müsste aber doch eigentlich gehen - Roland Ziegler weiß doch da bestimmt Bescheid.
Geht, aber nur über Umweg. Eine Möglichkeit ist COM, und damit auf die Windows-Plattform beschränkt. Eine andere ist CORBA, somit auch zwischen Prozessen. (Umgekehrt, Einbinden von C++ in .Net, ist deutlich einfacher, sogar ohne C++/CLI oder Managed C++.)

Nur - auf einem Micro-Controller hat man doch üblicherweise keine volle Betriebsystemumgebung. Allerdings gibt es ja heutzutage diverse Kästchen, auf denen die mobilen oder Micro-Editionen einer Java- oder .Net-Plattform zu installieren sind.

Wenn das alles nicht gilt, stattdessen C oder C++ mit klassischem Cross-Compiler genutzt werden soll (C++ erfordert zusätzlich einen Calling-Standard, denn in nativem ausführbaren Code gibt es keine OO), dann bleibt die Frage, auf welchem API man denn da aufsetzen kann. Berkeley Sockets würde ich mir vorstellen. Multithreading spielt natürlich auch wieder eine Rolle (ich gehe mal vom entsprechenden Kernel aus). Man braucht also auch ein IPC-API, mit Thread- und Verriegelungs-Funktionen.

Implementieren würde man dann analog zu dem Vorschlag in C#. Das "Pattern", also die Vorgehensweise, ist ja identisch.

Andreas K.
Beiträge: 82
Registriert: 22.01.2007 18:01:17
Wohnort: Nürnberg

Re: I/O Fahrpultsoftware für C++

#10 Beitrag von Andreas K. »

@ Roland

8o ?(

Den Artikel werde ich unkommentiert an meinen Schwager weiterleiten!

MfG Andreas

protonmw (Marc)
Beiträge: 300
Registriert: 06.05.2009 10:59:49
Wohnort: Freiberg(Sachs)

Re: I/O Fahrpultsoftware für C++

#11 Beitrag von protonmw (Marc) »

Roland, du hast das missverstanden!

nicht auf den µC soll das Programm sondern auf den PC...

EDIT: Um sowas auf nen µC zu bringen brauchts dann schon nen 32bit ARM oder ähnliches
Zuletzt geändert von protonmw (Marc) am 18.02.2010 18:38:01, insgesamt 2-mal geändert.
MfG Marc

"Wir genießen das Leben in vollen Zügen!"

Benutzeravatar
Roland Ziegler
Beiträge: 5508
Registriert: 04.11.2001 22:09:26
Wohnort: 32U 0294406 5629020
Kontaktdaten:

Re: I/O Fahrpultsoftware für C++

#12 Beitrag von Roland Ziegler »

Ich hab bei mir etwas "quick and dirty"-Code für Windows gefunden, ist eine Mischung aus C und (prozeduraler) C++-Notation. "Windows"-spezifisch scheint aber aber nur das Include des Winsock-API, was sich von original Berkeley nur in Nuancen unterscheidet. Ich weiß auch nicht mehr, welche Anteile von mir sind. #define für Konstanten benutze ich eigentlich seit 15 Jahren nicht mehr. Ich stelle das mal hier ein, ohne jede Gewähr. Und ich hoffe, dass keine Rechter Dritter verletzt werden. Bitte, bitte nicht als Ersatz für eine gescheite OO-Implementierung nehmen. Ich vermute, es ging damals nur um einen "Gangbarkeitsversuch", aufbauend auf zugeliefertem Code-Fragment. Das Ergebnis zeigt den Umgang mit den Sockets in C/C++, und den grundsätzlichen Kommunikationsaufbau. Mehr nicht.

Nach all den "Disclaimern" hier der Code:

Code: Alles auswählen

#include <stdio.h>
#include <time.h>
#include "winsock2.h"

//--------------------------------------------
// protocol version
#define VERSION           2

//--------------------------------------------
// commands
#define HELLO             1
#define ACK_HELLO         2
#define NEEDED_DATA       3
#define ACK_NEEDED_DATA   4
#define DATA              0x0a

//--------------------------------------------
// sub-commands
#define DATA_CTRLSTAND    0x0a
#define DATA_FINAL        0

//--------------------------------------------
// id for control stand client
#define CLIENT_CTRLSTAND  2


//--------------------------------------------
// data value ids
#define KEINE_FUNKTION                                    0
#define GESCHWINDIGKEIT                                   1
#define DRUCK_HAUPTLUFTLEITUNG                            2
#define DRUCK_BREMSZYLINDER                               3
#define DRUCK_HAUPTLUFTBEHAELTER                          4
#define ZUGKRAFT_GESAMT                                   5
#define ZUGKRAFT_PRO_ACHSE                                6
#define STROM                                             7
#define SPANNUNG                                          8
#define MOTORDREHZAHL                                     9
#define UHRZEIT_STUNDE                                   10
#define UHRZEIT_MINUTE                                   11
#define UHRZEIT_SEKUNDE                                  12
#define LZB_ZIEL_GESCHWINDIGKEIT                         13
#define LZB_AFB_SOLL_GESCHWINDIGKEIT                     14
#define LZB_ZIELWEG                                      15
#define FAHRSTUFE                                        16
#define FENSTER_3D                                       17
#define AFB_SOLL_GESCHWINDIGKEIT                         18
#define DRUCK_HILFSLUFTBEHAELTER                         19
#define LM_PZB_1000HZ                                    20
#define LM_PZB_500HZ                                     21
#define LM_PZB_BEFEHL                                    22
#define LM_PZB_ZUGART_U                                  23
#define LM_PZB_ZUGART_M                                  24
#define LM_PZB_ZUGART_O                                  25
#define LM_LZB_H                                         26
#define LM_LZB_G                                         27
#define LM_LZB_E40                                       28
#define LM_LZB_EL                                        29
#define LM_LZB_ENDE                                      30
#define LM_LZB_V40                                       31
#define LM_LZB_B                                         32
#define LM_LZB_S                                         33
#define LM_LZB_U                                         34
#define LM_LZB_PRUEFEN                                   35
#define LM_SIFA                                          36
#define LM_HAUPTSCHALTER                                 37
#define LM_GETRIEBE                                      38
#define LM_SCHLEUDERN                                    39
#define LM_GLEITEN                                       40
#define LM_MG_BREMSE                                     41
#define LM_H_BREMSE                                      42
#define LM_R_BREMSE                                      43
#define LM_HOCHABBREMSUNG                                44
#define LM_SCHNELLBREMSUNG                               45
#define LM_NOTBREMSUNG                                   46
#define LM_TUEREN                                        47
#define LM_TFZ_NUMMER                                    48
#define LM_MAX_TFZ_GESCHWINDIDIGKEIT                     49
#define LM_UHRZEIT                                       50 // TDateTime, 8 Byte
#define SCHALTER_FAHRSTUFEN                              51
#define SCHALTER_FUEHRERBREMSVENTIL                      52
#define SCHALTER_DYN BREMSE                              53
#define SCHALTER_ZUSATZBREMSE                            54
#define SCHALTER_AFB_GESCHWINDIGKEIT                     55
#define SCHALTER_AFB_EIN_AUS                             56
#define SCHALTER_MG_BREMSE                               57
#define SCHALTER_PZB_WACHSAM                             58
#define SCHALTER_PZB_FREI                                59
#define SCHALTER_PZB_BEFEHL                              60
#define SCHALTER_SIFA                                    61
#define SCHALTER_HAUPTSCHALTER                           62
#define SCHALTER_MOTOR_EIN_AUS                           63
#define SCHALTER_FAHRTRICHTUNG                           64
#define SCHALTER_PFEIFE                                  65
#define SCHALTER_SANDEN                                  66
#define SCHALTER_TUEREN                                  67
#define SCHALTER_GLOCKE                                  68
#define SCHALTER_LOKBREMSE_ENTLUEFTEN                    69
#define SCHALTER_SCHLEUDERSCHUTZBREMSE                   70
#define LM_DREHZAHLVERSTELLUNG                           71
#define LM_FAHRTRICHTUNG_VOR                             72
#define LM_FAHRTRICHTUNG_ZURUECK                         73
#define SCHALTER_SIGNUM                                  74
#define LM_LZB_ZIELWEG_AB_0                              75
#define LZB SOLL_GESCHWINDIGKEIT                         76
#define LM_BLOCK_BIS_ZU_DEM_DIE_STRECKE_FREI_IST         77 // String 
#define SCHALTER_LUEFTER                                 78
#define LM_GNT_G                                         79
#define LM_GNT_U                                         80
#define LM_GNT_B                                         81
#define LM_GNT_S                                         82
#define HINTERGRUNDBILD                                  83
#define PLATZHALTER_NACHTINSTRUMENT                      84
#define STRECKEN_KM                                      85
#define TUEREN                                           86
#define AUTOPILOT                                        87
#define REISEZUG                                         88
#define PZB_SYSTEM                                       89
#define FRAMES_PER_SECOND                                90
#define FUEHRERSTAND_SICHTBAR                            91
#define NAECHSTER_BLOCKNAME                              92 // String
#define NAECHSTES_GLEIS                                  93 // String   
#define BREMSHUNDERTSTEL                                 94
#define BREMSSTELLUNG                                    95
#define ZUGDATEI                                         96 // String 
       


//--------------------------------------------
// a string in delphi
// no 0-termination !
#pragma pack (1)
struct DelphiString {
  unsigned char length;
  unsigned char string [255];
};
#pragma pack ()

//--------------------------------------------
// union for data value types returned
union DataValues {
  DelphiString valString;
  double valDateTime;
  float valFloat;
};

//--------------------------------------------
// get the length of a value data field
int getDataValLen (unsigned char idData, DataValues * pVal) {
  int len;
  len = 0;
  
  switch (idData) {
  default:
    len = sizeof(float);
    break;
  case LM_BLOCK_BIS_ZU_DEM_DIE_STRECKE_FREI_IST:
  case NAECHSTER_BLOCKNAME:
  case NAECHSTES_GLEIS:
  case ZUGDATEI:
    if (!pVal)
      break;
    len = pVal->valString.length + 1;
    break;
  case LM_UHRZEIT:
    len = sizeof (double);
    break;
  }

  return len;
}

//--------------------------------------------
// send a datagram, executable function 
int sendDatagramExe (SOCKET * pSock, unsigned short int cmd, unsigned short int * pSubCmd, char * data, int datalen) {

  // long int assumed as 4 byte
  unsigned long int len;
  int bytesSent;
  
  unsigned short int ncmd;
  unsigned short int nsubcmd;
  
  // network byte order
  ncmd = htons (cmd);

  len = datalen + 2; // sizeof (short int);
  
  if (pSubCmd) {
    len += 2;
    nsubcmd = htons (*pSubCmd);
  }

   //no need to send TCP datagrams in one go
   //TCP will pack automatically

   //datagram len
  bytesSent = send(*pSock, (char*)&len, 4, 0 );
  if (bytesSent != 4)
    return -1;

  // datagram command
  bytesSent = send(*pSock, (char*)&ncmd, 2, 0 );
  if (bytesSent != 2)
    return -1;

  // datagram sub command
  if (pSubCmd) {
    bytesSent = send(*pSock, (char*)&nsubcmd, 2, 0 );
    if (bytesSent != 2)
      return -1;
  }

  // datagram data
  if (datalen > 0) {
    bytesSent = send(*pSock, data, datalen, 0 );
    if (bytesSent != datalen)
      return -1;
  }

  printf( "Command %d sent, total length = %d\n", cmd, len );

  return 0;
}

//--------------------------------------------
// send a datagram, wrapper for calls w/o sub-command 
int sendDatagram (SOCKET * pSock, unsigned short int cmd, char * data, int datalen) {
  return sendDatagramExe (pSock, cmd, 0, data, datalen);
}

//--------------------------------------------
// receive a datagram, incl. basic checks
int receiveDatagram (SOCKET * pSock, unsigned short int * pCmd, char* pData, int* pDatalen) {
  long int len;
  long int datalen;

  int bytesRecv;
  
  unsigned short int ncmd;

  // receive header
  bytesRecv = recv( *pSock, (char*)&len, 4, 0 );
  if (bytesRecv != 4)
    return -1;

  if (len <= 2 || !pCmd)
    return -1;

  // receive command
  bytesRecv = recv( *pSock, (char*)&ncmd, 2, 0 );
  if (bytesRecv != 2)
    return -1;
  
  *pCmd = ntohs (ncmd);

  datalen = len - 2;
  if (datalen > *pDatalen)
    return -1;

  // receive data
  bytesRecv = recv( *pSock, pData, datalen, 0 );
  if (bytesRecv != datalen)
    return -1;

  *pDatalen = datalen;

  return 0;
}

//--------------------------------------------
// send & receive HELLO datagram
// client name hard coded in demo
int primitiveHello (SOCKET * pSock) {
  char helloData[] = {VERSION, CLIENT_CTRLSTAND, 4, 'D', 'e', 'm', 'o'}; 
  unsigned short int cmd;
  int result;
  char replyData;
  int replySize;

  cmd = HELLO;
  result = sendDatagram (pSock, cmd, helloData, sizeof(helloData));
  if (result < 0) 
    return -1;

  replySize = sizeof(replyData);
  result = receiveDatagram (pSock, &cmd, &replyData, &replySize);
  if (result < 0) 
    return -1;

  if (cmd != ACK_HELLO || replyData != 0)
    return -1;

  printf( "\"Hello\" primitive completed.\n" );
  return 0;
}

//--------------------------------------------
// send & receive NEEDED_DATA datagram, executable function
int primitiveDataExe (SOCKET * pSock, unsigned short int dataCmd, unsigned char * idData, int idDatalen) {
  int result;
  char replyData;
  int replySize;
  unsigned short int cmd;

  cmd = NEEDED_DATA;
  result = sendDatagramExe (pSock, cmd, &dataCmd, (char*)idData, idDatalen);
  if (result < 0) 
    return -1;

  replySize = sizeof(replyData);
  result = receiveDatagram (pSock, &cmd, &replyData, &replySize);
  if (result < 0) 
    return -1;

  if (cmd != ACK_NEEDED_DATA || replyData != 0)
    return -1;

  return 0;
}

//--------------------------------------------
// send & receive NEEDED_DATA datagram, wrapper for actual subscription
int primitiveData (SOCKET * pSock, unsigned char * idData, int idDatalen) {
  int result;
  result = primitiveDataExe (pSock, DATA_CTRLSTAND, idData, idDatalen);
  if (result < 0) 
    return -1;
  printf( "\"Needed Data\" primitive completed.\n" );
  return 0;
}

//--------------------------------------------
// send & receive NEEDED_DATA datagram, wrapper for terminator
int primitiveDataFinal (SOCKET * pSock) {
  int result;
  result = primitiveDataExe (pSock, DATA_FINAL, 0, 0);
  printf( "\"Needed Data Final\" primitive completed.\n" );
  return 0;
}

//--------------------------------------------
// connect to server, address hard coded to local in demo
int connectServer (SOCKET * pSock) {
  // Initialize Winsock.
  WSADATA wsaData;
  int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
  if ( iResult != NO_ERROR )
    printf("Error at WSAStartup()\n");

  // Create a socket.
  *pSock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );

  if (  *pSock == INVALID_SOCKET ) {
    printf( "Error at socket(): %ld\n", WSAGetLastError() );
    WSACleanup();
    return -1;
  }

  // Connect to a server.
  sockaddr_in clientService;

  clientService.sin_family = AF_INET;
  clientService.sin_addr.s_addr = inet_addr( "127.0.0.1" );
  //clientService.sin_addr.s_addr = inet_addr( "192.168.0.2" );
  clientService.sin_port = htons( 1435 );

  if ( connect(  *pSock, (SOCKADDR*) &clientService, sizeof(clientService) ) == SOCKET_ERROR) {
    printf( "Failed to connect.\n" );
    WSACleanup();
    return -1;
  }

  printf( "Connected.\n" );
  return 0;
}


//--------------------------------------------
// init a session
int initSession (SOCKET * pSock) {
  int result;

  // send HELLO
  result = primitiveHello (pSock);
  if (result < 0)
    return -1;

  // IDs for subscription
  unsigned char neededData[] = {
    GESCHWINDIGKEIT, 
    LM_PZB_1000HZ, 
    LM_PZB_500HZ,
    LM_UHRZEIT,
    NAECHSTER_BLOCKNAME,
    ZUGDATEI
  }; 
  
  // send NEEDED_DATA
  result = primitiveData (pSock, neededData, sizeof(neededData));
  if (result < 0)
    return -1;

  // finish
  result = primitiveDataFinal (pSock);
  if (result < 0)
    return -1;

  printf( "Session initialized.\n" );

  return 0;
}


//--------------------------------------------
// handling unknown IDs
void handleDataDefault (unsigned char idData) {
  printf ("Data id = %d\n", idData);
}

//--------------------------------------------
// sample of handling float value (single precision)
void handleDataFloat (unsigned char idData, float val) {
  printf ("Data id = %d, float val = %5.1f\n", idData, val);
}

//--------------------------------------------
// sample of handling bool value
void handleDataBool (unsigned char idData, float val) {
  int boolVal = val == 1;
  printf ("Data id = %d, bool val = %d\n", idData, boolVal);
}

//--------------------------------------------
// month lengths for handling Delphi format
int MonthLength [] = {31,28,31, 30,31,30, 31,31,30, 31,30,31};

//--------------------------------------------
// sample of handling weird Delphi date & time format
void handleDataTime (unsigned char idData, double val) {
  // lep years w/ century exceptions
  double OneYearInDays = 365.25;
  
  // days is integral part of value
  int days = (int)val;
  
  // time of day is fractional part of val
  double time = val - days;
  
  // simplified handling of century exception
  if (days > 100 * OneYearInDays)
	  days --;

  int year = (int)(days / OneYearInDays);
  
  days -= (int)(year * OneYearInDays);

  year = year + 1900;
  int leapyear = year % 4 == 0;
  int leapyear100 = year % 100 == 0;
  int leapyear400 = year % 400 == 0;

  leapyear = leapyear && (!leapyear100 || leapyear400);
  if (leapyear)
    MonthLength[1] = 29;
  else
    MonthLength[1] = 28;

  int idx = 0;
  while (idx <= 11 && MonthLength[idx] <= days) {
    days -= MonthLength[idx];
    idx++;
  }

  int month = idx + 1; 

  // time of day in secs
  int secs = (int)(time * 3600 * 24);

  int hour = secs / 3600;
  secs = secs % 3600;

  int min = secs / 60;
  secs = secs % 60;

  tm tim;
  tim.tm_year = year - 1900;
  tim.tm_mon = month - 1;
  tim.tm_mday = days;
  tim.tm_hour = hour;
  tim.tm_min = min;
  tim.tm_sec = secs;
  tim.tm_isdst = 0;

  char timstr [32];
  strftime (timstr, 32, "%d.%m.%Y %H:%M:%S", &tim); 

  printf ("Data id = %d, date/time val = %s\n", idData, timstr);
}

//--------------------------------------------
void handleDataString (unsigned char idData, DelphiString * pVal) {
  pVal->string[pVal->length] = 0;
  printf ("Data id = %d, string val = \"%s\"\n", idData, pVal->string);
}

//--------------------------------------------
// receiving and processing data values from server
int receiveData (SOCKET * pSock) {
  char buf [2048];
  
  int result;
  unsigned short int cmd;
  char idData;
  DataValues * pDataValues;
  int datalen;
  int idx;

  datalen = 2048;

  result = receiveDatagram (pSock, &cmd, buf, &datalen);
  if (result < 0)
    return -1;

  if (cmd != DATA)
    return -1;

  // data body may contain more than one value
  idx = 0;
  while (idx < datalen) {
    idData = buf[idx++];
    pDataValues = (DataValues*)&buf[idx];
    
    idx += getDataValLen (idData, pDataValues);


    switch (idData) {
    default:
      handleDataDefault (idData);
      break;
    case GESCHWINDIGKEIT: 
      handleDataFloat (idData, pDataValues->valFloat);
      break;
    case LM_PZB_1000HZ: 
    case LM_PZB_500HZ:
      handleDataBool (idData, pDataValues->valFloat);
      break;
    case LM_UHRZEIT:
      handleDataTime (idData, pDataValues->valDateTime);
      break;
    case NAECHSTER_BLOCKNAME:
    case ZUGDATEI:
      handleDataString (idData, &pDataValues->valString);
      break;
    }


  }
  return 0;
}

//--------------------------------------------
// main function of demo program
int main(int, char**) {

  SOCKET sock;

  int result;

  result = connectServer (&sock);
  if (result < 0)
    return 0;

  result = initSession (&sock);
  if (result < 0)
    return 0;

  printf( "Entering endless data loop. Ctrl/C to abort.\n" );

  while (result == 0)
    result = receiveData (&sock);

  return 1;
}

Andreas Karg
Beiträge: 4718
Registriert: 28.04.2002 12:56:00
Kontaktdaten:

Re: I/O Fahrpultsoftware für C++

#13 Beitrag von Andreas Karg »

Bissi viel blöde Tipparbeit, die 1000 #defines. Ich hab's mir damals etwas leichter anders aufwändig gemacht und die Originaldatei vom TCP-Server in eine Liste eingelesen, die ich wiederum in serialisierter Form als Ressource in meine DLL eingebunden habe. Ist eigentlich ziemlich wenig Arbeit, wenn man mal rausgefunden hat, wie's geht. Letzteres war der größte Aufwand, aber ich will ja schließlich was dazulernen.

Benutzeravatar
Roland Ziegler
Beiträge: 5508
Registriert: 04.11.2001 22:09:26
Wohnort: 32U 0294406 5629020
Kontaktdaten:

Re: I/O Fahrpultsoftware für C++

#14 Beitrag von Roland Ziegler »

Aus den #defines in C sollten in C++ enum-Werte werden. Lässt sich mit jedem besseren Text-Editor recht zügig umsetzen ohne alles neu zu tippen. Deswegen war ich ja etwas irritiert, als ich dieses Teil gefunden hatte und rein schaute. Ohne enums (bzw C-#defines) würden die Switch-Cases nicht funktionieren, denn die brauchen feste Werte zur Compile-Zeit.

Es ist immer die Frage, wie groß man den Aufwand treibt. Bei einer überschaubaren und mittelfristig stabilen Schnittstelle würde ich zur festen Codierung der Telegrammauswertung raten. Wobei man im professionelleren Ansatz die Socket-Ebene von der Telegrammebene natürlich komplett trennt. (Hatte ich vermutlich auch für C# vorgeschlagen.)

Andreas Karg
Beiträge: 4718
Registriert: 28.04.2002 12:56:00
Kontaktdaten:

Re: I/O Fahrpultsoftware für C++

#15 Beitrag von Andreas Karg »

Die Liste der Messgrößen ist bei mir auch eine reine Komfortfunktion für den Benutzer der DLL. Man braucht nicht die Größe Nummer siebenundvierzigeinhalb anfordern, sondern kann bequem den Namen als Klartext anfordern. Außerdem brauchte ich die Liste sowieso, weil in der der Datentyp der Größe definiert ist. Stichwort Typsicherheit und so für den Anwender.

Andreas K.
Beiträge: 82
Registriert: 22.01.2007 18:01:17
Wohnort: Nürnberg

Re: I/O Fahrpultsoftware für C++

#16 Beitrag von Andreas K. »

@ Roland:

Sieht ja recht "vernünftig" aus.

Da aber meine Programmierkenntnisse auf dem Turbo Pascal aus meiner Zeit vom Gymnasium baut, werde ich es einfach meinen persönlichen Entwicklungsingenieur vorlegen. :D

Hab ich schon gesagt, dass das Turbo Pascal noch von 5,25″-Diskette zum booten war! :dösen

Oh Gott, bin ich alt! ;(

MfG Andreas

Benutzeravatar
Roland Ziegler
Beiträge: 5508
Registriert: 04.11.2001 22:09:26
Wohnort: 32U 0294406 5629020
Kontaktdaten:

Re: I/O Fahrpultsoftware für C++

#17 Beitrag von Roland Ziegler »

In der Schule hatten wir dieses Modell: http://en.wikipedia.org/wiki/Programma_101" target="_blank, war schon etwas betagt.

Andreas K.
Beiträge: 82
Registriert: 22.01.2007 18:01:17
Wohnort: Nürnberg

Re: I/O Fahrpultsoftware für C++

#18 Beitrag von Andreas K. »

Dann waren unsere 386 ja richtige Highend Geräte. :rofl

Aber lassen wir das, sonst kommt man ja noch ins philosophieren!

Wenn ich mir vorstelle, was sich in den zwanzig Jahren getan hat, was aus meinen ersten 486 25MHz Computer geworden ist.

Da war man noch stolz auf eine 200 MB Festplatte ;D

MfG Andreas

Antworten