Avatar billede svinth Nybegynder
08. februar 2000 - 11:40 Der er 14 kommentarer og
1 løsning

MVC++6 && Com port komponent

Jeg har via et indlæg her på eksperten fundet følgende com port komponent (hedder det komponent i c++?):

http://codeguru.developer.com/network/serial.shtml

Jeg har brugt den, ved at modificere eksemplet der står på siden, som følger:

void CSyncTestDlg::OnConnectionOpen()
{
  CSerial serial;
  if (serial.Open(2, 9600))
  {
    char teststr[256];
    char buffer[20];
    static char* szMessage = "AT\r";

    AfxMessageBox("");//Workaround???

    int nBytesSent = serial.SendData(szMessage, strlen(szMessage));
    ASSERT(nBytesSent == strlen(szMessage));
    sprintf(teststr, "Sent: \"");
    strcat(teststr,szMessage);
    strcat(teststr,"\", size=");
    itoa(nBytesSent,buffer,10);
    strcat(teststr,buffer);
    AfxMessageBox(teststr);
   
    char* lpBuffer = new char[500];
    int nBytesRead = serial.ReadData(lpBuffer, 500);
    sprintf(teststr, "Returned: ");
    strcat(teststr,lpBuffer);
    AfxMessageBox(teststr);
    delete []lpBuffer;
   
  }
  else
    AfxMessageBox("Failed to open port!");
  serial.Close();
}

Problemt er linien med kommentaren //Workaround???
Den skal være der for at AT kommandoen giver et resultat.
Bemærk desuden at jeg i forhold til eksemplet har modificeret linien:

    static char* szMessage[] = "AT\r";

fra eksemplet, til

    static char* szMessage = "AT\r";

(naturligvis med min egen streng!)

Jeg har nu 3 spørgsmål i en:

1) Hvorfor virker det kun når jeg bruger linien med kommentaren //Workaround??? ? (100 point)

2) Kalder man Serial.cpp og Serial.h for en komponent eller hvad kalder man dem? (Ja, jeg er vant til Delphi :) (5 point)

3) Kan min måde at håndtere strenge på forbedres og hvordan? (15 point)

Svante
Avatar billede rbnstudio Nybegynder
08. februar 2000 - 11:44 #1
Prøv evt en anden com component.
ComThread 4.....
Den kan anbefales.

http://www.protogene.com/people/giles/builder.html
Avatar billede svinth Nybegynder
08. februar 2000 - 11:47 #2
Med MVC++6 i overskriften, mener jeg Microsoft Visual C++ 6.
Ikke C++ Builder 4, 3 eller 1 :)

Svante
Avatar billede dmk Nybegynder
08. februar 2000 - 11:54 #3
Jeg vil forsøge at svare på 3. Din streng håndtering kan forbedres meget. strcat er bestemt ikke den bedste måde at håndtere strenge på. Følgende kan skiftes ud:

    sprintf(teststr, "Sent: \"");
    strcat(teststr,szMessage);
    strcat(teststr,"\", size=");
    itoa(nBytesSent,buffer,10);
    strcat(teststr,buffer);

-->  sprintf(teststr, "Sent: \"%s\", size=%d", szMessage, nBytesSent);

sprintf kan tage parametre som %s der betyder, at "her skal der stå en streng", og %d der betyder, at "her skal der stå et tal". Derved kan du få lavet hele din streng med et enkelt kald til sprintf.

DMK
Avatar billede dmk Nybegynder
08. februar 2000 - 11:56 #4
Med hensyn til spg. 1, så har det nok et eller andet med timing at gøre. Prøv at sætte en
Sleep(2000); ind i stedet, og se om det giver samme resultat.

DMK
Avatar billede rbnstudio Nybegynder
08. februar 2000 - 11:57 #5
svinth: Åh...det havde jeg ikke set
Avatar billede svinth Nybegynder
08. februar 2000 - 12:00 #6
Spørgsmål 3 besvaret af dmk...
dmk: Sleep virker også! Jeg leder videre, hvis jeg får det ordnet ordentligt, er pointene her også dine :)

Svante
Avatar billede dmk Nybegynder
08. februar 2000 - 12:02 #7
Er der ikke en tilstand på din serial du skal checke på, før du eksekverer videre? Hvis serial.open fx. laver sin egen tråd, som så lige skal processere noget færdigt, får du må lave en SendData, så må der også være en måde at checke denne tilstand på, så du slipper for at lave en Sleep, som ikke er nødvendig?

Jeg kender ikke din komponent, så jeg kan ikke rigtig komme med andet end nogle gæt.

DMK
Avatar billede dmk Nybegynder
08. februar 2000 - 12:09 #8
Med hensyn til spørgsmål 2:
Jeg tror det du mener med en komponent er "noget jeg kan se på skærmen". En cpp- og en h-fil er ikke det samme som en komponent. I dit tilfælde med serial indeholder serial.cpp og serial.h nok kun koden til serial komponenten, og derfor kan du da godt sætte lighedstegn imellem de to filer og din komponent. Men generelt kan en cpp og en h indeholde MANGE komponenter.

Ordet "komponent" kan i øvrigt også misforståes. Jeg ville nok vælge at kalde det en klasse, og når du laver en instans af klassen vil jeg kalde det et "objekt af klassen serial". Men igen, der kan være adskillige klasser i samme cpp og h fil.

Forholdet imellem cpp og h er i øvrigt heller ikke ligetil. Man kunne fx. have forestillet sig, at man lavede en "serial.h" fil til at definere en masse klasser til io-håndtering på serielporten. Men man kunne så vælge at lave 3 cpp filer, som implementerede 3 forskellige klasser, alle defineret i serial.h. Cpp og h filerne behøver derfor heller ikke at have navnesammenfald.

Og til sidst behøver du jo i øvrigt slet ikke have en cpp fil. Du kan implementere alle funktionerne direkte i h-filen, enten ved at lave implementationen direkte i klasse-definitionen, eller ved at lave alle funktioner inline, hvilket gør at alle funktionerne SKAL implementeres i header filen.

DMK
Avatar billede soepro Nybegynder
08. februar 2000 - 13:15 #9
Ad 1)
Jeg tror også det har noget med timingen at gøre. Det du skal være opmærksom på, er at kompeneten kører som en tråd - dvs. som en selvstændig process. Din 'Serial.Open()' er derfor et kald/signal til en anden process - og det kræver lidt tid at starte processen igen. (Igen fordi constructor'en til tråden er lavet med "suspend", dvs. tråden starter sovende og "vågner" først når du laver 'Open' kaldet.) Ligeledes kunne man godt forestille sig at dit modem også havde behov for lidt tid til at "opfange" buad-rate osv.

Du kan selvfølgelig være "heldig" at komme ud over dette, ved at lægge et delay (Sleep) ind i din kode - men i sagens natur med anvendelsen af tråde er det ingen sikkerhed. Den rigtige måde må være at checke status på Com-porten inden du begynder at sende den første streng. Du skal hvae fat i sorucen til komponenten, for at kunne tilføje et sådant kald. (TComThread er shareware.)

Jeg har selv anvendt komponenten til et simpelt "chat" program via et NULL-modem kabel, og der har jeg ingen problemer - men der sender programmet jo heller ikke noget, før jeg beder den om det. (Og jeg er nok tilpas langsom.)

Ad 2)
VB anvender også terminologien 'Component', så mon ikke det også hedder det i MVC.

Ad 3)
dmk har fuldstændig ret. sprintf har derudover et ret anvendelig "krølle", nemlig at man kan angive MAX længden af variable del af strengen som en del af "substitution flaget" (%s, %d osv.):

sprintf (strengVar, "Her er mit navn : %.10s", charVar);

Her bevirker '%.10s" at der max udskrives 10 tegn af strVar efter 'Her er mit navn: '. Det faste antal kan også udskiftes med en '*', hvor det aktuelle antal så skal skrives som en separate parameter. På den måde kan du undgå at få flyttet flere tegn over i strengVar end der er plads til:

const char *fixTxt = "Her er mit navn :";
sprintf(strengVar, "%s%.*s", fixTxt, sizeof(strengVar)-strlen(fixTxt)-1,
                          charVar);

(Fidusen med const'en her er at jeg skal bruge længden af den faste tekst, for at kunne beregne hvor mange tegn yderligere (af charVar) som der er plads til i strengVar. (-1 fordi der skal bruges et tegn til '\x0')
Avatar billede soepro Nybegynder
08. februar 2000 - 13:18 #10
dmk >> Du er åbenbart lidt hurtigere på tasterne end jeg er - jeg kan se at vi er enige.
Avatar billede svinth Nybegynder
08. februar 2000 - 13:19 #11
Jeg anvender stadig ikke TComThread og ikke C++ Builder :)

Svante

PS: Spørgsmål 2 og 3 er lukkede.
Avatar billede dmk Nybegynder
08. februar 2000 - 13:27 #12
Hej Soepro

Hvis du vil undgå at skrive ud over bufferen med en sprintf, så vil jeg da foreslå at du bruger _snprintf i stedet for at lave en const char* til den faste streng, og lave en strlen af denne.

_snprintf(StrengVar, MAX_BUFFER, "Her er mit navn: %s", CharVar);

DMK
Avatar billede svinth Nybegynder
08. februar 2000 - 13:30 #13
dmk: Du scorede alle pointene, tillykke :)
Den endelige løsning hedder:

void CSyncTestDlg::OnConnectionOpen()
{
  CSerial serial;
  if (serial.Open(2, 9600))
  {
    char teststr[256];
    static char* szMessage = "AT\r";//ATD96738377;\r
   
    Sleep(1);

    int nBytesSent = serial.SendData(szMessage, strlen(szMessage));
    ASSERT(nBytesSent == strlen(szMessage));
    sprintf(teststr, "Sent: \"%s\", size=%d", szMessage, nBytesSent);
    AfxMessageBox(teststr);
   
    char* lpBuffer = new char[500];
    int nBytesRead = serial.ReadData(lpBuffer, 500);
    sprintf(teststr, "Returned: \"%s\"", lpBuffer);
    AfxMessageBox(teststr);
    delete []lpBuffer;
  }
  else
    AfxMessageBox("Failed to open port!");
  serial.Close();
}

Så alt hvad jeg har gjort (efter at have grædt færdigt over den ukommenterede kildekode), er at indsætte sleep(1);, samt selvfølgelig at have rettet mine strenge. Mange tak for hjælpen!

Svante
Avatar billede dmk Nybegynder
08. februar 2000 - 13:36 #14
Okay, det er jo fint at det har løst dit problem, men du skal være opmærksom på, at du ikke nødvendigvis har løst det helt. At sætte en Sleep på 1 millisekund ind er muligvis ikke altid nok!

Det burde nok være noget i stil med:

while (serial.NotReadyYet()) Sleep(10);

Men som sagt, jeg kender ikke din komponent, så jeg er ikke klar over hvad din "NotReadyYet" funktion hedder, og hvordan den skal bruges. Men den findes, det er jeg sikker på!

DMK
Avatar billede soepro Nybegynder
08. februar 2000 - 13:43 #15
Ad 1)
Har du inkluderet alle de rettelser der er beskrevet i de forskellige kommentarer der ligger på "codeguru". Der er bl.a. nogle rettelser omkring timeout og "open" af com-porten. Hvad med den "oprindelige" CSerial klasse ??? Kunne den ikke løse dit problem ??? Det virker lidt risikabelt at anvende COM1 som en "gemen" fil, samtidigt med at status osv. checkes ved "direkte" angang til COM-registrene. (I CSerial er det hele samlet i een klasse.)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester