[BCB6] COM-port met statemachine

Pagina: 1
Acties:

  • Scheppie
  • Registratie: Juli 2002
  • Laatst online: 07-04 17:41
De situatie is als volgt:
Ik heb een PC-applicatie die communiceert via de COM-port met een microcontrollerbordje.
Voor het programmeren van de PC-applicatie gebruik ik componenten van TurboPower Async Professional 4.06.
De COM-port wordt gebruikt i.c.m. een statemachine om netjes een protocol te volgen.
Hierbij worden datapaketten uitgewisseld. Nu wordt in de statemachine de data ontvagen en weggeschreven in een AnsiString (dit is altijd zo met dit component daar is helaas niets aan te doen). Dit is vervelend want in de paketten komen ook NULL characters voor de AnsiString is hierdoor incompleet omdat, zoals jullie vast wel weten worden AnsiStrings afgesloten met een NULL character.

Ik heb geprobeerd om direct vanuit de statemachine de COM-port aan te spreken en om op de COM-port direct een trigger te zetten die de binnengekonen data aan de statemachine doorgeeft. Helaas raakt de statemachine in de war, die heeft zelf ook triggers op de COM-port staan waardoor hij in de soep loopt.

Verder kan ik wel in de statemachine een Memo-veld vullen waarbij bij een NULL character een nieuwe regel aangemaakt wordt. Dit is alleen niet zo betrouwbaar als er meerdere NULL characters achter elkaar komen wordt er niet idere keer een nieuwe regel aangemaakt.
Ook weet ik dat een AnsiString eigenlijk een array is en dat bij een NULL character een nieuwe lijn aangemaakt wordt, ik weet alleeen niet of ik gepasserde lijnen ook nog terug kan lezen (indexnr?). De c_str methode heb ik geprobeerd maar gaat hier niet op.

Dus heeft iemand een idee hoe ik een AnsiString kan reconstrueren, of misschien wel een andere oplossing voor dit probleem?

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 08-04 12:26
Als ik het goed heb is een AnsiString de normale C-string, dwz een array van bytes.

Als je niet met een eindmarkering kunt werken ( zoals bij een \0 het geval is ) moet je met een lengte gaan werken: maw bij elk pakket wat je binnenkrijgt moet je blijven bijhouden hoeveel bytes erin staan.

Nu weet ik niet hoe een AnsiString werkt, maar bijv de std::string heeft ook contructors en methodes die een lengte als parameter hebben, deze is redelijk te gebruiken voor dit soort dingen. Hij kijkt zelf helemaal niet naar een terminator oid. Alleen als jem als zodanig gaat gebruiken is het opeens een normale C-string.

Misschien kan dat met een AnsiString ook wel. En zoniet dan moet je een ander component zoeken, want ik moet eerlijk zeggen dat ik nooit gesnapt heb waarom er bij communicatie verschil wordt gemaakt tussen binaire data die toevallig ascii tekens zijn en andere data. starttekens, stoptekens al die dingen zorgen alleen maar voor problemen, en een protocol die in veel gevallen niet bruikbaar is en op z'n minst oneconomisch.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • Scheppie
  • Registratie: Juli 2002
  • Laatst online: 07-04 17:41
Helaas is het niet mogelijk om een lengte op te geven voor de AnsiString.
Hieronder heb ik even de standaard functie gezet welke aangeroepen wordt als de statemachine getriggerd wordt. Hierin heb ik Labels en een Memo-veld gebruikt om de binnengekomen data te bekijken.

void __fastcall TForm1::GSBlockStateGetDataString(TObject *Sender,
AnsiString DataString)
{
Label4->Caption = DataString;
iLength = DataString.Length();
Label5->Caption = iLength;
Memo1->Lines->Add(DataString);
}

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Een AnsiString is een Delphi String en kan weldegelijk #0 bevatten midden in de string. Zolang je functies gebruikt die daar ook mee om kunnen gaan is er niets aan de hand. Een #0 geeft niet in AnsiStrings en niet in C-Strings een nieuwe lijn aan. Dat is nog altijd #13#10 onder Windows. Omdat de WinAPI veelal met C-Strings werkt waarbij een #0 het einde van een string aangeeft wordt een AnsiString ook altijd extra afgesloten met een #0. Een TMemo is een wrapper om het windows multi line edit control en daar heb je dus te maken met C-Strings. Tot zover de theorie. Ik kan niet zien waar je probleem vandaan komt, maar met deze theorie moet je vast wel een oplossing bedenken. De AnsiString is iig niet het probleem. En waarom een TMemo gebruiken en niet een TStringList?

/edit
Oeps. Ik zie nu dat het BCB is en niet Delphi. Toch zou de AnsiString in BCB hetzelfde moeten reageren als in Delphi.

[ Voor 8% gewijzigd door LordLarry op 07-03-2006 09:21 ]

We adore chaos because we like to restore order - M.C. Escher


  • schoene
  • Registratie: Maart 2003
  • Laatst online: 16:57
Ik kan LordLarry's verhaal bevestigen in BCB. Je kan zonder problemen '\0' karakters gebruiken in AnsiString.

Dit is eenvoudig te testen door:
C++:
1
2
3
4
AnsiString test="Dit is een test";
ShowMessage (test.Length ());
test[4] = '\0';
ShowMessage (test.Length ());


Wat ik me wel herinner is dat bvb een LoadFromFile van TStrings stopt op het moment dat je een '\0' tegenkomt. Misschien ervaar je een gelijkaardig fenomeen?

[ Voor 8% gewijzigd door schoene op 07-03-2006 09:50 ]


  • Scheppie
  • Registratie: Juli 2002
  • Laatst online: 07-04 17:41
schoene schreef op dinsdag 07 maart 2006 @ 09:49:

Wat ik me wel herinner is dat bvb een LoadFromFile van TStrings stopt op het moment dat je een '\0' tegenkomt. Misschien ervaar je een gelijkaardig fenomeen?
Ja ik denk dat dit idd het geval is aangezien een AnsisString wel NULL characters kan bevatten.
Zijn er manieren om dit te omzeilen?

  • schoene
  • Registratie: Maart 2003
  • Laatst online: 16:57
post anders eens een code-snippet, waardoor het makkelijker is om te zien wat fout gaat.

  • Scheppie
  • Registratie: Juli 2002
  • Laatst online: 07-04 17:41
Ik weet inmiddels waarom het Memo-veld wel gevuld wordt en de Labels niet.
Doordat er op de statemachine een datatrigger zit die een fixed length heeft (523 bytes).
Zal de GSBlockStateGetDataString functie uitgevoerd worden zoveel als dat er NULL characters in de 523 bytes zitten.

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 08-04 12:26
Scheppie schreef op dinsdag 07 maart 2006 @ 10:10:
Ja ik denk dat dit idd het geval is aangezien een AnsisString wel NULL characters kan bevatten.
Zijn er manieren om dit te omzeilen?
Dan moet AnsiString constructors/methoden hebben die naast een buffer ook een lengte als parameter hebben. Het voorbeeld dat gegeven wordt door schoene is een beetje raar omdat ook deze (constante) buffer een afsluitende \0 heeft.

Maar als je bijvoorbeeld dit kan doen (pseudo)

C++:
1
2
3
4
char buffer[] = { 0, 0, 1, 2 ,3 ,4 ,0 , 5, 7, 255 };

AnsiString s( buffer, 6 );
s.Append( buffer + 6, 4 );


ben je eruit.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • Scheppie
  • Registratie: Juli 2002
  • Laatst online: 07-04 17:41
Dan zit er niets anders op dan de componenten van TurboPower te dumpen en zelf een statemachine te proggen. Hierbij gebruik makende van het hierboven gegeven voorbeeld.
Wel vreemd dat de componenten geen NULL characters ondersteunen, dit lijkt me toch geen uitzonderlijke situatie bij het versturen van datapakketten.

Iig bedankt voor jullie hulp :)

Toevoeging 9-03-2006
Ik heb inmiddels een werkende oplossing:
Een zelf geprogrammerde state-machine die met "commandovlaggen" werkt (ieder commando heeft zijn eigen vlag)
Een trigger op de COM-port, die naar het start character op de inputbuffer kijkt.
Deze trigger start een timer (afhankelijk van de baudrate).
Als de timer afgelopen is het inputbuffer uitlezen.
De data analysren/controleren en de juiste functie uitvoeren aan de hand van de commandovlag en de binnengekomen data.

Niet erg fancy maar het werkt :)

[ Voor 43% gewijzigd door Scheppie op 09-03-2006 15:59 ]

Pagina: 1