Hallo zusammen,
ich habe mir einen Webserver mit ENC28J60 und einem AT89C51ED2
"zusammengebastelt" also Hardware und Software zum grösstenteil selber
geschrieben. Jetzt habe ich mich mal ein bisschen mit den AVR
beschäftigt und dachte ich könnte diesen Webserver mal auf einen ATMEGA
644 portieren. Eigentlich funktioniert soweit auch alles. Ich habe
allerdings ein problem damit eine Webseite per TCP zu versenden. Die
Webseiten liegen bei mir im Flash und sollen über einen buffer im ram an
den ENC weitergereicht werden. Solange die Webseite < 256 Bytes ist
funktioniert das ganze auch wunderbar. Ist die Webseite grösser dann
haut zuerst die Checksummenberechnung nicht mehr hin, mache ich sie noch
grösser dann hängt sich der Kontroller auf. Die Beispiele im Tutorial
habe ich auprobiert, auch die in der GCC Faq, aber das Ergebniss ist
immer das selbe. Beim 8051 gibt es ja das Iram mit 256 Bytes, gibt es
das beim AVR auch? Wie schaffe ich es die 4K Ram beim AVR komplett zu
nutzen?
Mein Buffer im Ram habe ich so angelegt:
unsigned char buffer[1518]; // ENC Sende und Empfangs Buffer
Meine Website liegt hoffentlich so im Flash:
PROGMEM unsigned char HtmlTest[] =
{
//Die Website
}
Und so versuche ich die Daten aus dem Flash in den Buffer zu kopieren:
unsigned int http_data_out (PGM_P pointer, unsigned int seq_no)
{
unsigned char *http_buffer;
unsigned int new_length = 0, zgr = 0;
http_buffer = &buffer [ 58 + zgr ];
while ( pgm_read_byte ( pointer + zgr ) )
{
http_buffer[zgr] = pgm_read_byte ( pointer + zgr );
zgr++;
}
new_length = zgr;
send_tcp_data (new_length, seq_no);
return new_length;
}
Segmentierung gibt es beim AVR nicht. Kling eher danach als ob du
irgendwo bei deinen Berechnungen einen unsigned char als index in den
Speicher benutzt der dann natürlich überläuft. Kann ein Überrest einer
"Iram-Optimierung" sein ;-)
An der obigen Funktion kanns nicht liegen. Ist zwar unnötig kompliziert,
aber ich kann keinen Fehler sehen.
P.S.
Ich würde das so machen. Allerdings noch nicht dem Compiler übergeben,
kann sein dass noch Typecast für 'pointer' notwendig sind.
Hallo Werner,
unnötig kompliziert, damit könntest Du recht haben, aber ich beisse mir
schon seit 2 wochen die Zähne an diesem Problem aus. Dementsprechend
Banane sieht der Code mittlerweile auch aus. Eine "IRam optimierung"
gibt es bei dem Originalcode vom AT89C51ED2 leider auch nicht, weil ich
da natürlich alles "Datenfressende" in das XRAM verschoben habe. Aber
der Hinweis das es eigentlich so funktionieren müsste, hilft mir schon
mal, dann lag ich ja nicht ganz falsch. Sind doch ein paar unterschiede
zwischen 8051 und AVR.
Ich werde jetzt noch mal versuchen den betreffenden Code umzuschreiben.
Gruß aus Köln
Frank
Du schreibst ja:
> Ist die Webseite grösser dann haut zuerst die Checksummenberechnung> nicht mehr hin, ...
Ich würde mich als erstes mal dort umsehen, wo die Checksumme berechnet
wird. Hast du vielleicht dort einen 8-Bit-Index?
Außerdem: Wie sieht es mit dem Gesamtspeicherbedarf deiner Software aus?
Es könnte auch sein, dass du mit dem Stack kollidierst.
Hallo nochmal,
also ich habs nochmal umgeschrieben und es ist immer noch dasselbe.
Bei 256 Bytes ist schluss mit lustig. Eigentlich macht die Routine doch
nichts anderes wie die Adresse der Daten im Flash zu bekommen und dann
Byte für Byte in das Ram zu kopieren. Also das Ram ist 1518 - 58 = 1460
Bytes gross und die Daten im Flash sind 328 Byte gross. Ist auch schön
mit /0 terminiert lt. Ponyprog. In diesem zustand sehe ich mit Wireshark
noch das TCP Paket, aber die checksumme stimmt schon nicht mehr, da ja
die daten im buffer nicht mehr mit den aus dem Flash zu lesenden Daten
übereinstimmt.
So langsam bin ich mit meinem Latein am Ende.
Hat vieleicht noch jemand eine Idee ?
Gruß aus Köln
Frank
Hallo Stefan,
Speicherbedarf:
Program = 9356 Bytes
Data = 1732 Bytes
Ich weiss nicht wie man den Speicherverbrauch noch weiter aufdröseln
kann, ich bin noch nicht so lange auf dem AVR unterwegs, beim SDCC ging
das über das .map File. Das gibt es zwar hier auch, aber ich habe noch
nicht raus welche speicherbereiche wo stehen. Den Speicherverbrauch oben
zeigt mir das makefile an. Die CRC Routine schliesse ich erstmal aus, da
sie auf dem AT89C51ED2 ja läuft. Ich hänge sie aber mal mit an.
Gruß aus Köln
Frank
Zu erkennen ist, dass du die
pgm_read_byte / pgm_read_byte_near
Funktion nutzt. Nun ist es aber möglich, dass deine Daten an einer
Adresse liegen, an die ein 16Bit-Pointer nicht gelangt (Adresse >=
2^16). Dafür gibt es die
pgm_read_byte_far
Funktion [1]. Allerdings werden Daten vom Linker/Locator i.d.R.
möglichst im unteren Bereich abgelegt, sodass es meist keine Probleme
damit gibt. Knifflich wird es halt erst bei vielen Daten/großen
zusammenhängenden Blöcken im Programmspeicher.
Just my two cents.
[1] http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html
Hallo die ???,
danke für den Tip, das wird dann wohl das nächste Problem werden. Beim
ED2 hatte ich am schluss mit Website und Debugmeldungen 50K voll.
Gruß aus Köln
Frank
> Meine Website liegt hoffentlich so im Flash:> PROGMEM unsigned char HtmlTest[] =>> {> //Die Website> }
Du hoffst nur oder hast du den Flash-Inhalt kontrolliert, ob die Daten
wie gewünscht dort drin stehen? Die Position des PROGMEN Schlüsselworts
ist ungewöhnlich. Im AVR-GCC-Tutorial wird das anders gemacht.
In deiner Kopierroutine wird ja das Nullbyte nicht mitkopiert. Ist das
Absicht? Hier die Kopierroutine etwas gestrafft:
/* http_buffer bzw. buffer ist jetzt NICHT mit '\0' abgeschlossen! */
16
17
send_tcp_data(count,seq_no);
18
returncount;
19
}
Wie sieht deine send_tcp_data (count, seq_no); aus?
Die scheint ja für die Prüfsummenberechnung zuständig zu sein. Ist dort
vielleicht eine Laufvariable nur unsigned char statt unsigned int?
Stefan hat nicht unrecht, ungewöhnlich ist es - es sollte aber in den
meisten Konstellationen funktionieren. Ich rate dazu, die vordefinierten
Typen zu verwenden:
1
typedefvoidPROGMEMprog_void
2
typedefcharPROGMEMprog_char
3
typedefunsignedcharPROGMEMprog_uchar
4
typedefint8_tPROGMEMprog_int8_t
5
typedefuint8_tPROGMEMprog_uint8_t
6
typedefint16_tPROGMEMprog_int16_t
7
typedefuint16_tPROGMEMprog_uint16_t
8
typedefint32_tPROGMEMprog_int32_t
9
typedefuint32_tPROGMEMprog_uint32_t
10
typedefint64_tPROGMEMprog_int64_t
11
typedefuint64_tPROGMEMprog_uint64_t
Das Beste ist, wenn du dein kompilierbares Projekt hier mal hochlädst.
Hallo Stefan,
dieser PROGMEM Syntax ist aus dem Quellcode vom Simon Schulz (AVRETH1).
Ursprünglich hatte ich es so geschrieben:
const char HtmlTest[] PROGMEM =
{
//Die Website
}
Aber weil es alles nicht so lief wie es sollte, habe ich mir das bei den
anderen Webserverprogrammierern angeschaut. Macht aber auch keinen
unterschied, habe ich gerade noch mal ausprobiert. Das mit der /0
Terminierung ist ok, wird bei TCP auch nicht mit übertragen.
Hier noch die send Routine:
void send_tcp_data (unsigned int datlen, unsigned int nextseq)
{
struct IP_header *IP_packet;
struct TCP_header * TCP_packet;
struct IP_Pseudoheader *IP_pseudopacket;
IP_packet = (struct IP_header *)&buffer[ETHERNET_HEADER_LENGTH];
TCP_packet = (struct TCP_header *)&buffer[ETHERNET_HEADER_LENGTH +
IP_HEADER_LENGTH];
IP_pseudopacket = (struct IP_Pseudoheader
*)&buffer[ETHERNET_HEADER_LENGTH + IP_HEADER_LENGTH -
IP_PSEUDOHEADER_LENGHT];
MakePseudoHeader (IP_packet->IP_DestinationIP,0x06,
TCP_HEADER_LENGHT + datlen);
MakeTCPHeader
(TCP_packet->TCP_DestinationPort,ChangeEndian32bit(TCP_packet->TCP_Ackno
wledgeNumber),ChangeEndian32bit(TCP_packet->TCP_SequenceNumber)+nextseq,
TCP_PSH_FLAG | TCP_ACK_FLAG, datlen , TCP_packet->TCP_Options);
MakeIPheader(IP_pseudopacket->IP_DestinationIP,0x06,TCP_HEADER_LENGHT+da
tlen);
enc28j60PacketSend( ETHERNET_HEADER_LENGTH + IP_HEADER_LENGTH +
TCP_HEADER_LENGHT + datlen,buffer);
}
Gruß aus Köln
Frank
Ist das eine fertige (auf AVR getestete) Library oder muss man da tiefer
einsteigen? Die Arbeitsfunktion zur Prüfsumme sehe ich nicht und kann
sie auch nicht beurteilen, die ist noch tiefer angesiedelt.
In deiner http_data_out hast du 58 als magic number. Kannst du die
in Beziehung zu den Makrokonstanten in der send_tcp_data setzten, um
Bufferoverflows (Bufferbereiche werden in Headerbereiche kopiert oder
umgekehrt) auszuschliessen?
Hallo nochmal,
wenn ich sehe wie der Code nach mühevoller bearbeitung im
Vorschaufenster aussieht, dann wird mir ganz anders.
Ich hänge das was ich habe einfach mal dran. Achtung es wimmelt vor
furchtbaren Kommentaren, es hagelt warnings, aber es läuft. Bis auf TCP.
:(
Kompilieren lässt sich das ganze mit WinAVR 20071221.
ACHTUNG SICHERHEITSHINWEIS !!! ICH BIN AVR NEULING :)
Gruß aus Köln
Frank
Hallo Stefan,
das mit der 58 ist so:
Ich habe mir im RAM einen Bereich reserviert der 1518 Bytes gross ist.
Dann kommt zuerst der Ethernetheader mit 14 Bytes, dann IP Header mit 20
Bytes, dann TCP Header mit 24 Bytes grösse. Das 58te Byte stellt den
Startpunkt für meine HTTP Daten dar. Hier würde dann die eigentliche
Webseite landen. Das funktioniert für 256 Bytes und dann ist schluss.
Ich vermute die CRC routine ist ok, da sie auf dem ED2 ja auch
funktioniert hat. Ausserdem rechnet sie ja auch weiter, aber die Daten
im Paket hören einfach ab dem 256 Byte auf. Was mich an dieser ganzen
geschichte stört ist die Zahl 256. Es sind ja auch bereits 58 Bytes
Header im paket und nur bei der Kopierroutine aus dem Flash hört er
einfach auf in den buffer zu schreiben.
Nun gut der code ist gepostet, vielleicht sieht ja jemand noch etwas.
Gruß aus Köln
Frank
Das Archiv zu posten, war eine gute Idee. Die Bedenken wg.
Bufferoverflow kann man so schon zerstreuen. Die magische 58 ist
erklärbar. Den Rest schaue ich mir in Ruhe heute abend an.
Hallo zusammen,
vielen Dank nochmal an alle für eure Hilfe.
Als ich die Frage heute morgen reingestellt habe, hatte ich schon die
befürchtung das wird direkt als typische Anfängerfrage in der Luft
zerissen. Mit soviel Hilfe habe ich nicht gerechnet. Ich bin jetzt echt
platt !!
Gruß aus Köln
Frank
Nur nochmal für die Interresierten
Die Adresse von dem Funktionierende Webserver mit dem AT89C51ED2
http://colonia66.dnsalias.com/main.html
Da möchte ich gerne mit dem AVR weitermachen
Gruß aus Köln
Frank
In der Funktion http_data_out kann ich keine Probleme entdecken. Der
String aus HtmlTest wird sauber nach buffer kopiert. Alle 328 Zeichen.
Es findet auch später kein Überschreiben statt.
Aber kontrolliere mal diese Stelle in send_tcp_data (und ähnliche
Stellen in den anderen send_... Funktionen).
Ich denke, dass die Sequenznummer zuerst erhöht werden muss, bevor der
Wert von Little Endian (AVR) nach Big Endian (Network) gewandelt werden
muss (If TRUE Fall)
Das Versagen bei Paketen mit mehr als 256 Bytes Nutzdaten käme mir
plausibel vor, wenn z.B. ein Paket 256 Bytes Nutzdaten hat und durch die
falsche Erhöhung alle Folgepakete ausser dem ersten wg. falscher
Checksumme verworfen werden. Ich kann das aber nicht mit Bestimmtheit
sagen, weil ich eine minimale Version getestet habe mit willkürlichem
Aufruf von http_data_out, d.h. nicht weiss, wie du deine Seiten
auslieferst - alle 328 Bytes am Stück (s. Test) oder in kleineren
Portionen
main.c
1
#define DEBUG
2
3
#include<stdint.h> // ISO C99 Integer types
4
#include<avr/io.h> // ATTINY I/O's
5
#include<util/delay.h> // delay Lib.
6
#include<avr/pgmspace.h>
7
#include"global.h" //
8
#include"spi.h" //
9
#include"ethernet.h" //
10
#include"enc28j60.h" //
11
#include"timer.h" //
12
#include"dhcp.h"
13
#include"dns.h"
14
#include"sntp.h"
15
#include"udp.h"
16
#include<stdlib.h> //
17
18
#ifdef DEBUG
19
20
intmain(void)
21
{
22
// http_data_out(array[0], 0);
23
http_data_out(HtmlTest,0);
24
while(1);
25
}
26
27
#else
28
29
// Original Code aus main.c
30
31
#endif
Add:
Mit der Zeile
http_data_out(array[0], 0);
hatte ich Probleme. Da stimmt noch was nicht mit der Verknotung der
Pointer auf die Strings.
Hallo Stefan,
mit dem erhöhen der Sequenznummer und dann nach Big Endian wandeln,
könntest Du durchaus recht haben, kommt mir jetzt auch ein bisschen
merkwürdig vor. Ich werde das gleich mal ausprobieren. Obwohl ich mir
dann noch nicht erklären kann, warum das Problem nicht auch schon bei
kleineren Paketen auftritt.
In dem einen Fall schicke ich ein Paket mit < 256 Bytes HTTP Daten und
danach ein TCP_FIN paket und Wireshark sagt alles ok und die Webseite
wird im Browser angezeigt.
In dem anderen Fall schicke ich auch nur ein Paket allerdings mit 328
Bytes HTTP Daten und danach ein TCP_FIN Paket und Wireshark meckert das
CRC nicht stimmt und die Seite wird im Browser nicht angezeigt.
Man sieht im 2. fall auch das sich die Checksumme ändert und er diese
Routine weiter abarbeitet. Der Kontroller ist danach noch mit einem Ping
erreichbar. Erst wenn ich noch mehr HTTP Daten sende (~1K) dann schmiert
der Kontroller ab und ist dann auch nicht mehr erreichbar.
Die ursprungliche Senderoutine beim ED2 war so, das die HTTP daten so
groß sein konnten wie es erforderlich ist, und die http_data_out
Funktion hat die Daten dann in Ethernetkonforme Häppchen zerteilt.
Also sollen bis zu 1450 Bytes HTTP Daten am Stück gesendet werden und
wenn dieses problem beseitigt ist mache ich mich wieder an das zeteilen
der HTTP Daten.
Die Zeile:
http_data_out(array[0], 0);
Ist noch ein Überbleibsel aus diversen versuchen aus dem Flash zu lesen.
In der GCC Faq gibt es einen Abschnitt wo beschrieben ist, wie man
komplette Strings im Flash ablegt und anschliessend wieder ausliest.
Dort wurde ein Array aus Zeigern auf die Strings im Flash angelegt und
diese Strings wurden dann so adressiert. Kann man also vergessen, fliegt
jetzt sowieso wieder raus.
Vielen Dank und gruß aus Köln
Frank
Hallo nochmal,
also das mit der Sequenznummer ist so wie ich es gemacht habe korrekt.
Ich habe jetzt nochmal eine Verbindungssequenz mit Wireshark mitgeloggt.
Beispiel:
SYN - Seq_No 94 65 17 5E
SYN_ACK - Seq_No 94 65 17 5F SYN_ACK = Seq_No + 1
ACK - Seq_No 94 65 1A 13 ACK = Seq_No + Datenlänge (692 Bytes)
Also muss die Sequenznummer nach dem Wandeln auf Big Endian erhöht
werden.
Gruß aus Köln
Frank
Hallo Stefan,
ich habe mal weitergemacht und kann nun sagen, das das Problem irgendwie
im bereich der TCP Routine zu suchen ist. Ich habe mal spasseshalber mit
der pgm_read_byte routine die Website in ein UDP-Paket gepackt und
gesendet. Dann kann ich mit Wireshark auch das komplette Datenpaket mit
den 328 Byte Nutzdaten sehen. Im Umkehrschluss heisst das, das sowohl
der buffer als auch die Flashkopierfunktion ok sind.
Gruß aus Köln
Frank
> Im Umkehrschluss heisst das, das sowohl der buffer als auch die> Flashkopierfunktion ok sind.
Das war auch meine Schlussfolgerung gestern abend.
Ich habe einen Plan für heute abend - ich werde mit einer modifizierten
http_data_out Pakete mit 250 bis 270 Bytes Nutzdaten konstruieren und
auf Absonderlichkeiten bei der Berechnung der Checksummen achten, wenn
die 8-Bit Grenze überschritten wird.
Als Nutzdaten plane ich Nullbytes zu verwenden, denn deren Inhalt sollte
bei dieser Checksummenberechnung nicht in die Summe eingehen. Lediglich
die Anzahl kommt an verschiedenen Stellen ins Spiel und eventuell gibt
es da Merkwürdigkeiten.
Hallo Stefan,
Die Checksummenberechnung hatte ich jetzt auch im verdacht, aber diese
CRC Funktion wird bei mir auch bei den udp_send funktion angewendet und
da hat Wireshark, bei mehr als 256 Bytes, nichts auszusetzen. Ziemlich
seltsam das ganze.
Ich prüfe jetzt nochmal diese Pseudoheader und IPHeadergeschichten
vieleicht liegt das problem ja auch hier.
Gruß aus Köln
Frank
Frank schau dir mal in send_tcp_data den Aufruf von MakeTCPHeader an und
die Funktion selber - es wird beim Aufruf und in der Funktion selber die
Endianess berechnet. Ist das richtig so?
Oh, da ist eine Mischung bei der Endianess in der Source. Deshalb auch
das doppelte Umwandeln im obigen Aufruf.
Ich kann mir gut vorstellen, dass gerne eine Umwandlung zuviel oder
zuwenig durchflutscht. Deshalb würde ich das Ganze nochmal peinlich
genau unter die Lupe nehmen und folgende Regeln beachten/anwenden:
1/ Es werden die bekannten Makros htonl (d.h. host-to.network-long),
htons, ntohl und ntohs verwendet, um von network byte order auf /host
byte order/ umzurechnen.
Du hast zwar 32-Bit und 16-Bit Umwandelfunktionen, aber die sind für
beide Richtungen gleich benannt. Dadurch fällt es beim Lesen der Source
unnötig schwer, die Plausibilität des jeweiligen Codes sofort zu
beurteilen.
Beim AVR wären die Makros:
2/ Ausserhalb der Paketheader werden "normale" Variablen, Konstanten
und Funktionsargumente immer in der host byte order angegeben. D.h.
Das Programm (und der debuggende Zuschauer) arbeitet immer mit der
Zahlendarstellung, die auf dem Host üblich ist.
Bsp:
1
2
// IP Adresse für ENC 192.168.0.123 = = c0.a8.00.7b
3
MyIP.LONG=0xc0a8007b;
3/ Beim Lesen aus den Paketheadern werden immer die ntohs bzw. ntohl
Makros verwendet. D.h. in den Headern bleiben die Werte immer in der
network byte order aber werden im Programm in der host byte order
verarbeitet. Wenn solche Werte an Funktionen übergeben werden -
ebenfalls mit dem Makro in der host byte order.
Bsp 1:
1
MakeTCPHeader(
2
ntohs(TCP_packet->TCP_DestinationPort),
3
ntohl(TCP_packet->TCP_AcknowledgeNumber),
4
ntohl(TCP_packet->TCP_SequenceNumber+nextseq),
5
TCP_PSH_FLAG|TCP_ACK_FLAG,
6
datlen,
7
ntohl((unsignedlong)(TCP_packet->TCP_Options)));
8
// Anm.: ...->TCP_Options in MakeTCPHeader auf NULL checken!
4/ Beim Schreiben von Paketheadern werden die zugewiesenen Werte immer
mit den htonl bzw. htons aufbereitet und dann zugewiesen. D.h. auch hier
ist wieder sichergestellt, dass alle Werte in den Paketen immer in der
network byte order sind.
Bsp:
Ausserdem würde ich möglichst viele magische Zahlen wie buffer[14]...
durch Konstanten ersetzen, so wie es teilweise schon gemacht wurde.
Und last but not least - Mir persönlich gefällt der Stil mit // an jeder
Zeilenende nicht so gut. Beim Einfügen von Code oder Umschreiben ist das
meistens hinderlich (abgesehen von der verhunzten hier im Forum, deshalb
habe ich die Kommentare oben entfernt)
Das hört sich jetzt umfangreich an, ist aber überschaubar.
Guten Morgen Stefan,
Entschuldige das ich mich erst jetzt melde, aber konnte gestern erstmal
meinen PC neu aufsetzen. :( (Festplatte lagerschaden) Ist aber gerade
noch gutgegangen.
Nun zur Software:
Da werde ich mich wohl nochmal durchbeissen müssen. Die bekannten Makros
htonl htons ntohl und ntohs kannte ich bis jetzt noch nicht, aber so
etwas in der art hätte ich gerne von anfang an eingebaut. Ich bin
nämlich mehr wie einmal auf verdrehte IP Adressen reingefallen. Mit den
"magischen Zahlen" gebe ich Dir recht, ist wirklich schwer
durchschaubar, ist aber leider irgenwann eingerissen, weil mir das zu
viel schreibarbeit war. (z.B. buffer[ETHERNET_HEADER_LENGTH +
IP_HEADER_LENGTH + Datalength + usw.])
Das mit den Kommentaren am Zeilenende wird mit Sicherheit besser, das
dient mir im Moment dazu, meinen Code auch in einem halben Jahr noch zu
verstehen. In C bin ich nämlich auch noch nicht so lange unterwegs (ca 2
Jahre), in Assembler war das aber immer sehr Hilfreich. :)
Blöderweise habe ich die Hardware in der Firma liegengelassen, (jaja der
Karfreitag), aber die Software kann ich ja schon mal anfangen umzubauen.
Vielen Dank erstmal und Frohe Ostertage
Gruß aus Köln
Frank
No Panic ;-)
Manchmal tut ein bisschen Abstand ganz gut. Es fallen dann oft Bugs auf,
die sonst unbemerkt durchschlüpfen.
Das mit der Schreibarbeit kann ich verstehen. Das lässt sich aber mit
ein paar Makros beheben. Im Anhang eine Source, bei der das Durchgezogen
wurde.
Kommentare sind nicht schlecht. Was mühsam ist, ist deine Art die Zeilen
mitten im Statement umzubrechen, den Rest mit vielen Leerzeichen zu
füllen und dann auf einer festen Position mit dem Kommentar zu beginnen.
Das erschwert es neuen Code einzugeben, weil zuerst die Formatierung
gebrochen werden muss und dann ggf. wieder hergestellt werden muss.
In dem Anhang ist das komplette Projekt. Die wesentlichen Änderungen
stehen in comments.txt. Mach vor dem Austesten ein Backup deines
Projekts, ich denke zwar, dass alle Änderungen sauber mit SVERSION/STEST
gekapselt sind, aber sicher ist sicher. ARP, DNS, ICMP und DCHP habe ich
nixht explizit überarbeitet, nur die offensichtlichen Stellen.
Ich kann im Moment mangels realer Hardware nicht weiter testen. Nützlich
für die weitere Simulation im Debugger wären verschiedene Binärfiles mit
1/ einem korrekten TCP-Paket µC => PC (< 255 Zeichen)
2/ einen nicht korrekten TCP-Paket µC => PC (328 Zeichen HtmlTest?)
3/ einem TCP-Paket PC => µC, was ein Senden von 1/ oder 2/ auslöst
Wenn du mit Wireshark sowas mitschneiden kannst (ggf. von dem
funktionierenden Webserver) wäre das klasse. Auf den colonia66 komme
ich nicht drauf (Timeout bei der Abfrage) sonst hätte ich es selbst
probiert, Testdaten zu beschaffen.
Hallo Stefan,
da hast Du ja ganz schön gewirbelt. :) Ich lese mich gerade mal durch
deinen Code und muss sagen er ist wirklich besser lesbar. Wenn ich darf
würde ich einige Sachen gerne übernehmen. Der colonia66 Webserver ist am
besten zu jeder vollen Stunde erreichbar, da er dann eine mail
verschickt und die Zeit synchronisiert. Kann Du die Wiresharkdateien
lesen? Dann würde ich mal ein paar logs mit dranhängen.
Gruß aus Köln
Frank
Hallo nochmal,
hier die Wiresharkdateien, bei denen man den Fehler gut sehen kann.
Die 192.168.0.99 ist der anfragende PC, die 192.168.0.200 ist der
AVR-Webserver. Ich habe noch nichts an der Software geändert, dazu
brauch ich noch ein bisschen Zeit.
Gruß aus Köln
Frank
Mit den Dateien müsste ich heute abend zurecht kommen.
Entweder als Binärdatei behandeln und den interessanten Part mit einem
Hexeditor rauskopieren oder mit einem Analysetool (WinDump, Ethereal,
Snort) auslesen.
Hallo Stefan,
ich habe jetzt mal einen grossen Teil umgeschrieben und kann jetzt
zumindest schon mal ein positives Zwischenergebniss mitteilen. Mit 328
Bytes läuft es jetzt. :) Es scheint an der CRC Routine zu liegen.
Ich habe nach und nach die TCP Funktionen umgeschrieben und hatte immer
noch die selben Probleme. Nachdem ich die checksum Funktion ausgetauscht
habe ging es mit 328 Bytes. Wenn ich allerdings nochmal ca. 80Bytes
dranhänge dann hakt es wieder. Mit Wireshark kann ich das Paket dann
nicht mehr sehen, scheint so als würde der ENC das Paket dann als
ungültig verwerfen. Per ICMP ist der Webserver aber dann noch ereichbar.
Ausserdem wird jetzt die CRC bei UDP nicht mehr richtig gerechnet.
(checksum = 0xFFFF).
Im Anghang ist jetzt erstmal die Wireshark datei mit dem derzeitigen
Stand.
TCP 328 Bytes ok, DNS abfrage checksummenfehler bei UDP.
Gruß aus Köln
Frank
@Frank
Ich findes es schön das du an meinen Code weiterbastelt und ihn nach
einen AT89C51ED2 portiert hast oder es versucht und jetzt wieder auf
einen ATmega644. Was ich mir aber stark wünsche ist das du auch den
Urheber der eigentlichen Sourcen namentlich weiterhin erwähnst, da dies
in der dem Orginalsource beiliegenden GNU-Lizenz ausdrücklich verlangt
wird. Und da ich große Teile meines Sourcecode wiedererkenne + den
Signifikanten Stellen im Code selber würde ich mir das auch für die
Zukunft wünschen. Vielen DanK.
CA Dirk Broßwick
Das wäre/ist natürlich übel. Ehre wem Ehre gebührt und Lizenzen sind zu
beachten.
Vom Programm und den WinPCAP-Dumps her, kann ich trotz intensivem
Simulieren keine Problemursache ausmachen. Auffallend ist lediglich,
dass in dem "Nicht OK"-Mitschnitt die Antwort abgeschnitten ist. Bis zur
Übergabe an den enc28j60 ist in der Simulation der Sendebuffer jedoch
OK. Ich kann also nur spekulieren, dass das Problem in der Ebene
enc28j60 und tiefer liegt. In der Simulation kann ich z.B. kein Timing
testen, da müsste Hardwaredebugging z.B. über UART ran.
Hallo zusammen,
@Dirk
Du hast natürlich Recht, einige Grundlegende Teile des Sourcecodes
stammen aus Deinem Originalcode. Ich möchte hier auch niemand etwas
wegnehmen. Das was ich hier reingestellt habe ist meine derzeitige nicht
lauffähige bastelversion. Ich möchte mich hier auch nicht mit fremden
Federn schmücken. Ich bin immmer noch C anfänger und habe mir diverse
Webserverprogramme angeschaut. Die Teile die ich verstanden habe, und
die ich auch nicht viel anders hätte schreiben können, habe ich
implementiert.
Teile die ich nicht verstanden habe, habe ich selber geschrieben und
mich durch die entsprechenden Protokolle gewühlt. Viele sachen wie z.B
POP3 oder SMTP habe ich woanders gar nicht gefunden und selber
geschrieben. Deine DHCP Geschichte habe ich mir auch angesehen und die
lief bei mir z.B. gar nicht. Nach diversen änderungen lief das dann auch
an 4 verschiedenen DHCP Servern. Das habe ich Dir auch in diesem Thread
Beitrag "ENC28J60 Basics[Beispielprogramm in AVRGCC für atmega8]" geschrieben.
Ich habe kommentierungen so geändert das ich diesen Code verstehe, aber
alles erstmal nur für mich privat. Das hier noch die
Originalquellverweise fehlen war für mich selbst (zu Hause) erstmal
zweitrangig. Das jetzt dieser "private" Code hier ist, war nur so ein
Schnellschuss, da ich im moment an einem problem nicht weiterkomme.
Sollte dieses Problem beseitigt sein und ich meine ich müsste den
fertigen Code hier reinstellen dann sind auch die Quellenverweise für
die entsprechenden Codestellen wieder drin. Ich möchte das jetzt hier
aber auch nicht einfach so stehen lassen als würde ich mir nur Code
zusammenklauen und das dann als mein geistiges Eigentum "verkaufen"
wollen. Das ist nur für mich privat, ich handel nicht damit, ich
verkaufe nichts und ich verdiene kein Geld damit.
Sollte ich ich Dir mal bei Deinem Projekt helfen können, so werde ich
das auch gerne tun. ( sofern man das als C Anfänger kann )
Gruß aus Köln
Frank
Hallo Stefan,
ich denke auch, das ich mir jetzt erstmal eine RS232 schnittstelle an
den AVR hängen muss, um den Fehler weiter einzukreisen. Da muss ich aber
erstmal wieder bei Reichelt bestellen, da ich im moment keinen MAX für
3,3V habe.
Gruß aus Köln
Frank
@Frank
Nee, es geht ja auch nicht ums wegnehmen, das ist ja auch so gewollt,
deshalb steht ja der Source unter GPL :-). Es ärgert einen immer nur
wenn einer vergisst das es eben auch unter GPL steht. Da mein Code schon
in diversen Projekten verwendet wird, zwar nicht in der Version die du
benutzt hast, freue ich mich wenn ich lobend erwähnt werde :-). Der Code
auf den du baust ist zwar etwas älter denn er ist in der jetzigen schon
wesentlich überarbeitet worden.
Da ich auch meine Studienarbeit dadrüber schreibe und das Projekt sich
schon zu einem ganzen Framework entwickelt hat würde ich dir auch gerne
helfen b.z.w. die jetztigen Sourcen für einen ATMega2561 mit externen
RAM zukommen lassen. Diese lassen sich denke ich mal auch leicht für
einen ATMega644 anpassen, da die erweiterte Entwicklung für diesen
gedacht war. Wenn du noch Fragen haben solltest kannst du ja mal per PM
über Mikrocontroller.net schreiben.
CA Dirk
Hallo Dirk,
eigentlich geht die ganze Geschichte ja noch viel weiter runter.
Ich habe bis zu diesem Thread
Beitrag "ENC28J60 Basics[Beispielprogramm in AVRGCC für atmega8]" immer nur in Assembler
auf dem 8051 meine Programme geschrieben. Ich habe mehrmals versucht
einen einstieg in C zu bekommen, aber spätestens nach dem berühmten
"Hello World" hat sich das Thema schnell wieder erledigt. Als ich dann
diesen Thread gelesen habe, dachte ich ich könnte den ENC mit einem 8051
verheiraten, in Assembler. :( (Macht nicht wirklich spass)
Dann kamst Du mit deinem Source. Das war für mich im Prinzip der
Einstieg in C. Dieser Code war für mich als Einsteiger gut zu verstehen
und ich konnte viel lernen. Also habe ich das ganze für den 8051 und den
SDCC umgebaut und auch jede menge neu dazugeschrieben. Ich denke mit dem
jetzigen wissen, könnte ich auch versuchen das ganze Projekt selbst neu
zu schreiben, aber das macht in meinen Augen keinen Sinn.
Um es kurz zu machen:
Gäbe es nicht so Leute wie Du, die ihren Code veröffentlichen würden,
dann hätten es viele Einsteiger schwer, etwas zu lernen. Ich habe
seitdem, alle meine Assemblerprogramme auf C umgebaut.
Ich hoffe ich habe Dich nicht zu sehr geärgert ;) aber das war ganz
bestimmt keine absicht von mir.
Gruß aus Köln
Frank
ÄH, der ansicht war ich mit Assembler auch mal gewesen, aber das geht
nur bis zu einer bestimmt komplexzität gut, danach gehts einfach nicht
mehr da es sehr unübersichtlich wird und man mehr mit Registern und
ähnlichem beschäftigt ist als mit den Problem selber :-).
Das ist jetzt aber schon einige Zeit her. Der Webserver war auch das
erste wirklich große Projekt welches ich in C geschrieben haben. Aus
heutiger sicht ist mein Programmierstil nicht besonders gut gewesen. Man
lernt halt immer dazu. Am besten ist es wenn man richtig einsteigen
möchte erst mal am PC mit C zu programmieren um sich sicher zu sein wie
C arbeitet, zumal die möglichkeit des debuggens wesentlich einfacher
sind. Bücher sind dafür mit das beste Werkzeug und das lesen der Threads
hier im Forum. Nach und nach erschließen sich die möglichkeiten von C
einem wie von selbst und es fällt wesentlich einfacher ein Problem zu
lösen, da man irgentwann nicht mehr mit der Sprache an sich kämpft :-).
Da hilft aber nur üben, üben ... .
Aber zurück zum Sourcecode, da ich immer noch einige altlasten in meinen
Sourcen mit rumschleppe würde mich nochmal der Code zum DHCP-Client
interessieren, da ich diesen bis jetzt seid dem auch nicht mehr
angefasst habe. Du hattest geschrieben das dieser jetzt reibungsloser
funktioniert, hast du das Problem genauer gefunden? Und wenn ja, wo
liegen die probleme?
CA Dirk
Hallo Dirk,
ist jetzt auch schon fast wieder ein Jahr her, wo ich mich das letzte
mal mit dem DHCP-Client auseinandergesetzt habe. Aber hier hatte ich das
Problem mal beschrieben.
Beitrag "Re: ENC28J60 Basics[Beispielprogramm in AVRGCC für atmega8]"
Und zwar schickst Du bei der Funktion DHCP_SendDiscover keinen "Client
Identifier" mit. Das Problem taucht nicht bei jedem DHCP Server auf,
aber bei meinem Netgear konnte ich das schön beobachten. In Problemfall
bekommt der Server zwar den Request aber antwortet danach einfach nicht
mehr.
Vermutlich verwirft der Server das Paket einfach als ungültige Anfrage.
In dem oben im Thread angehängten Quellcode ist meine änderung bereits
mit eingebaut. Das kannst Du wahrscheinlich direkt mit einbauen.
Gruß aus Köln
Frank