From 8e785e4b7003b3a6fd3706442af410f2e6d2e6f2 Mon Sep 17 00:00:00 2001 From: Tristan Krause Date: Tue, 2 Apr 2019 10:59:37 +0200 Subject: [PATCH] speichern --- driver/drv/b15f.cpp | 3 +- driver/drv/b15f.o | Bin 27776 -> 27816 bytes driver/drv/usart.cpp | 24 ++- driver/drv/usart.h | 2 +- driver/drv/usart.o | Bin 30640 -> 31320 bytes driver/main | Bin 62096 -> 62096 bytes firmware/B15F.elf | Bin 13840 -> 14612 bytes firmware/B15F.hex | 411 ++++++++++++++++++++++----------------- firmware/global_vars.cpp | 16 +- firmware/global_vars.h | 16 +- firmware/main.cpp | 41 ++-- firmware/requests.cpp | 86 ++++---- firmware/selftest.cpp | 20 +- firmware/usart.cpp | 79 +++++++- firmware/usart.h | 27 ++- 15 files changed, 443 insertions(+), 282 deletions(-) diff --git a/driver/drv/b15f.cpp b/driver/drv/b15f.cpp index fc3f804..18cc93b 100644 --- a/driver/drv/b15f.cpp +++ b/driver/drv/b15f.cpp @@ -28,11 +28,12 @@ void B15F::init() // Temporärer Test - uint8_t block[] = {0, 1, 2, 3}; + uint8_t block[16]; while(1) { usart.writeBlock(&block[0], 0, sizeof(block)); usart.printStatistics(); + usleep(1000); } throw std::runtime_error("SCHLUSS"); diff --git a/driver/drv/b15f.o b/driver/drv/b15f.o index 79f3e7b4912fed69ad44b43b8659a526d8165a9b..bffe005539693d924f36c4a18563ea2c769f3179 100644 GIT binary patch delta 2011 zcma)6drVtZ7(b`&T>widE8*@s*?1X?kI=GBrgJTiVJ|Ya0uI`3ajT5N03*w`u(&9Y zO{KC*=jWpZjc77QjEmqU%l5|vTzDj!$c#>EVm6EtBGbv1D1YGaJGU2evc$xboZmU; z_x--dIp^Nf9;N+J8nROBV2)EK?3cS*J<4;s@p!R84mM|}mj-@5Aa@z=w-Q3+z_x4; zJY^hVvcn!oN_1+os>EJvLFl3xMfPvx!0&S4+8oZ&BQ_4t=?PJp`5)ju({5-tNnVe9 z;zpbtaP?2P2AFuqU`&4O`y)au zTi0=ndAR{@n#8psf71GGDCiQHzx?vZ5yS1v{?M+f;V@(;Wwm+afPSJljv2>`jhMLD z&E|7k?@Ij0|4kgMYT!xCuC!m*fg;HEZ?&3}s(&(HWn%6QUIJw2^FVcBRX?=z6E zr~n4?6a9$(sVA@N1;s!v>bJ1D0XML`Op`a^SR$OHq+F;ZZ81_@i{lRAQ%ar@KBmMk zG?6pPC9yTZUZx|&z>*i4%t2j|Y0W9UY)XH{P-wEA5L~7ZMN>NV?RYV)1)wf7iw-G) z%)gAZ3_5bZgpIb8!j^bKR+D?kK%yp#4dliD;9t}D0#i&l1OeN6`XShDBJGD!nm(S`l{qBGvX1&?=FhRxu3rDp7i$Q~FS| zat>#~ht~6&mBlaNtYd0~X%(--C@KYunm|3zb(}H*7BFLu694oD9UkA->TX!7Ho|mu zHkR>swTr$1B{ln`cQ_X<5@AOahD$Xfjlg#`xwHoaPpVXI%fhb}>NDWSE125uc zh#(d~6ww3HL6*&n*a8v6FhmbJg+BHc!l=grwni(x4&Fv5U4#hY97G$PI?FnBN46#_ oT?5`G%AXnWp@BIgcFzA&)~wb3VNQ-sT7X0gDQ9(f|Me delta 1870 zcma)5Z%kWN6u+nKODLAM4A`^G1qLiuvjJrykY$ttjt4qy>42(C$Db7xh!VGGr9@@6>K@OR@BFc`p@feqO1Mycp5f2&s{Nez`jpUh zrR0ahQmj?~F)BD+tduOonb2?A5Z6~0@3&@3zr-slrne>!8`h@%L-pRTIxy9eebBCi z^s^NST%D;f(JU32JYU}VuUWSKuUW!gn&tj_9vtuuzgY;dm~25TWGJ9J_h!@ z^gb}Z)XCn9d?NQIIy^eY_>aNL&DOB4-2C8xUNL8$Fu2V2KB>wa0Fp9kJ*6k0IDz$9 z*)S1#J?l>sc(5n$n?0M@18g!$lVck@YGmxc_&$wyn`6ca9L~>x^SCWvwvCgP#kOb_ z7;ECaDbjH(ZFXP3tF2?qrJsNl~P z_z%^-R|Hk;dxLj8?J?m)ZWF8^cw|`P?co`8P~MEqgd-}>adf0wsWt^~kF??!^nt)v z3j8!iJ+dt)nJ5Z=>_J-bw|3+2q}FRHuc-*?ySS}RhR;;|0zGxIZAx&~2+ms=By~@GZA{f-p#6f3e}@+$ zVc(N_n8f+#^60BFHuZuv5^PG5AdF|4ojB6G<8(_ZjA2^K8kD24wJ7nm(pZ_*G^}ZT zT&GJ#&(_U2lx@HZtvR}cRGexp#j>^pOlT{{0PRX!G2~;g%?TYCB|M05$O%?-5q^q6 zLN`WL2K-K_Ko?;h2K`Q*NyaIEDZLEsPTg`nmbaJEEd<-0L`4a$2pvucpo_2!gM?O$ z61ovy(end - start).count(); } - return n_read; + return 0; } int USART::write_timeout(uint8_t* buffer, uint16_t offset, uint8_t len, uint32_t timeout) @@ -150,23 +150,35 @@ void USART::writeBlock(uint8_t* buffer, uint16_t offset, uint8_t len) block_buffer[len + 2] = BLOCK_END; // send block + clearOutputBuffer(); + clearInputBuffer(); int n_sent = write_timeout(&block_buffer[0], 0, len + 3, us_per_bit * n_total); if(n_sent != n_total) throw std::runtime_error("fatal (send): " + std::to_string(n_sent)); + + /*for(uint8_t i = 0; i < len + 3; i++) + { + write_timeout(&block_buffer[i], 0, 1, us_per_bit * n_total); + //tcdrain(file_desc); + //usleep(1000); + }*/ // flush output data tcdrain(file_desc); - usleep(us_per_bit * n_total); + //usleep(us_per_bit * n_total * 10); // check response - int n_read = read_timeout(&aw, 0, 1, us_per_bit); + int n_read = read_timeout(&aw, 0, 1, us_per_bit * n_blocks_total * 10); for(uint16_t i = 0; i < 255 && n_read != 1; i++) { writeByte(0x80); // Stoppzeichen für Block - tcdrain(file_desc); + if(tcdrain(file_desc)) + { + std::cout << "drain failed" << std::endl; + } std::cout << "WARNING: read error (" << n_read << "), retry #" << (int) i << std::endl; - usleep(us_per_bit); + usleep(us_per_bit*100); n_read = read_timeout(&aw, 0, 1, us_per_bit); } diff --git a/driver/drv/usart.h b/driver/drv/usart.h index e375e8c..1659316 100644 --- a/driver/drv/usart.h +++ b/driver/drv/usart.h @@ -125,7 +125,7 @@ public: /***************************************/ constexpr static uint8_t CRC7_POLY = 0x91; - constexpr static uint8_t MAX_BLOCK_SIZE = 16; + constexpr static uint8_t MAX_BLOCK_SIZE = 64; constexpr static uint8_t BLOCK_END = 0x80; private: diff --git a/driver/drv/usart.o b/driver/drv/usart.o index ed30f7a6553023a2d3d5f8bc7674a12313c22898..a00541edc2ef963061d3ac4163d017a7c670e8a9 100644 GIT binary patch delta 8429 zcma)B3se+WnyzYS1?;A}5iANt0UJdlffgT-QLvjv3Pc5i##I{eg{Xj_fMlX+478!> z^d87>5+)OqaVBOoqqBP0sOyRmpOM6kx|>gMaolJ;cswLLBJdcA$Ebr_H~NL;7YpBB z{$4QX5#hdu@E{^IciWIpNT!J@LXA8^=*LXTn{`8ycDP zNll!^m71e`AuHcdBISy5vih`Ke>z;bxYTYbu-GkymSv}eF`W5wPj_*1@sn+>Lw5)A zeUNIL=xEF_S%t$t-P!DKsn5*ibND};wVBd6S*bEDCO$hlZu-}s@Usbr?+Axa6f0Xy zvlN@jW)c4FERF`t`m?KW3`IfV(0N%oC*xUMmOC?;Omf{8zP>{vw~~`Yd1VI~liitp z!l4scZkvXeLl6k3i>ljVvT{PhOG6+qWE(#jTp=SJ2w55(dfBzb6j$FDAk?qca@?$+ z&iM<@=Z0{cvrkqYRfQ9Jas5{s;gCqCxs9TSmR(h*L`$P>IvPN?$4TKVXKh3Ebrx3| zO_lS6;Jk;1@Z9`UKcXGVal#>+$(l6Ry+-d|>_-__zR7?k>TzBc8tfQ`4KoxV9QrIv zIotC@aWj?4nQ$9xGSZQPvNd67RaX9#qkKgQj^VwfdvT8A!x-Li3N9y zdsH2j8PG@>@K)2D;-&PdgYFLX>!N? zq4I>zl*IoQw%;U+b)_98i}vn}`n!B}XK^!Ty1cLISsc>2YAu#MA2gxK!5cB0y62Ly z29NwW4t5#Bp(r#UGMyKk6%YIRWLJaf2pU@@C;7+5;Y4tnwBQV#FmE=pw=Q5;ER1PD zf&^?cZJ<$Sn0vF1c>^ca4)p%kE9aXnrnX#Z4o zY|l(#jKh1y$`h{8T7Avb%98Sjnh0+;*g9RfMUrl*Kf_zLJ?tZXopT=b^}TN(p}PxA z6`lZGo;A7YZ3nkahWW%%DxzF7pYVt{-1|(;R7+j|pJe4*52bvQquiv^TfMkZ@D_pD zkd=H>lxp2icF#mr?l{dDUII~=okTh1uF!BFqe1Dui!yVC*@4QrzRSeXYj}c}00fIs z#wsTbg21(X1O|r~$;ZJ?F;?^ZeK>B2iT&blYNSNy6Ff1WxHaT{Utc@Q_a_vFg-1No zJur9wpVY~&W1jrhpE1ZO-&SeW+-)&c$n~cXx&~Xqr#j+XIU^n@IpTv`&U<}*n6o%? zB`g*W=ZttnX1T=*&Tf?;DJy5Zb$MK>GvwapwODnHI_bH>I?qzhJocZX^!8ln`Jkt* z=PDJ2SZO-^$Vc)YfmsvD{~lU2BK%xB30op`AV*Ar84yagxyci=to&0*RX zjogu8TBngaHB5Wcz+D-32dmgDXpb4VcLnXo2JSsUs~EW-gk89K_8GPHA>2tL-bFq) zYF`cE9vHQ)AzVv{7NpS~x>XyOuPu)%UcR<;^(y#ubY|P=F-Ns}8TZFaXq2=a5FZ;8 zGcPz-vmz)sIXyVh5*%j@ju3NK3Jy%97_RU-m5QLd(~QWzADwk_%904`^(Dz?(%rllJpS z4~bR&;BOA)w@~aRm2$ze<^+B>Mc$?TztjGG+MlQWCDKcO!Q@4A3H{zkok{DXGQ+@_ zB*K9je`uH-%BPSsJ`D~|79~6G!Vu2DRbaHFt?&%o7Pv841Vd6d{}z?rOZz*tH$Wxo zPoVu&+NaZg745gcC1hWw^H$pbn)Z9aJVlg_V;PA*4lh;Gc6bKvDv{Chh#DX-dN@A> zT2ML`&x!Obe6%6Wdi2eOM)wrBvm0lu3eX1$1P3^&fBhn~Hy@U3rX&(d!r;1V>mX%mbBtIG0Vm$*l18$&JK9S*m3`pJV`r6Wj>_61eMc7e265yO#33**TN-4oOJ#&@Y6;9w{(7y_BYzHrbqLV znR_xPeR4AGQ%IkbNaxerwkDVH@K#C)+)ptWr!0KhvLHXBcIE1dsxtbXJ}Iv?p>}j%v_b6ZmqNX%(eH z#2=7fCv0D;GGt%XKpC=|8TLDsCAnV*JFOyL4ewbKq;f_^QVT|8s^KB^5}!^aGtzw} z7y3xL(@8w-RPvJnlC6wnEkxQxsg&{f9}N3*m}?`xR@;1i-Be}Bx(Z>xP1M&g7JdSw z4fABvNwo|bs9s!TC8eOx5Mf4!PM^r2)i5)IL|vBQo5fsJh72{Z6E#0V&6SL1EnLVD z_3SF12Q$hA%+_J_VY7Xs-^bW11p92?=>HQsP_uQmZ}k7gcq@hW*$Mpf(2KnTA~QwU zm#NdIt9Nc9=zzJ1&X9Fbk!d07q~-;fDJKvWsFij4 zdPKaNDHJ-;#2#5EEn?6aLT{Bl@tH7}gDL zWLf(*^~aXPSq<$uB3}ZZ<8D@+N}K<89_VQO~jgux-8wwWwV> zPp7vGdo24p?3^dUgLyiBGkk}$D=33!`W8mU4i7yt`aKL<3-R+sz7#U%C+L5P2E8l$ z0uG|D*7+uWJ+#jkrB@g(Lro4@^()XjfPGVCY4ss8*S8|W^^c=|6XxcU8^l(WsblQV zP-Q$fiv7qc3|qxmsE00O8yL2m(R~HZ$ zU?*B&?-MUD794P40K1>jt%rwsB1~Fy1$LF88qf;avnd=y?mZpHz-bzgzy&xnq_ z49l+XJ;vN3Caf<9k^g28`6cS-fPwj2<-x7AK&*o|8HH-b@op6#xHI-a^kUJ`p|YeL z>^`{2;8w=kXAI76gRfMagv)M&2Mo?WP6(cNS1a8gEHOfTsU_k5hH)IJ;v~?w89Wxu zOGL*el_l4b4 zGx(Pb&c3_$FnA4z&s5&a<*zg!4^^7vgLUsu{$9gI+>gVwct)5401*$j35v z;yt)$cd~|_Vhq(X3RVVZ3lusV#!N&lAZA} z8Rw*tMXaRyk8S>Q+4iNPv;?)(r%En^n88LYt%2U9B8)1~@rR%VzdXd@Y#mH3NRZYe z>rL!UB94t{*kNmd@5@o7`le3U64+mWUor}G`o#>o4!Tfh4f0-#_`^&a(P;&}oqT+o zX&0q;@Z2jy{y-&-l=-(%hBA9#C-(2c1-r=ah4?~zI4smbL39B5z^dZ=`td7v9bZGv zv}Dh5aHD28zY2N_#{ywqrE)K!es_(IUjgnykzY(ciBVf+5V`DqzPPPxnTwaMk_fPo zfgHb5->OWoZMi5V`w{Ljo2$Mt<-kE?iw3Y2Dq96NkbPqS>-|=?8;mPN>FWWk_uE$} zSdc9uxl{eB4^Q;G87h(e1;dgD;P)xVabLFWS}}x&&XwWNzETg%RvOx_uB`KeH`Yvo z#x3Gs-_|WnsBH?5gelI5LA|`Ie;7vC3a{kOT|Z;^JQt814xyR z?R!4QRa(vT>*%1x+}#j)Kk& zsew1u56)p=te777V6?|pAfAa(QW2#wL_t$UszzQ0oj6oPLr^6eTn5>dsr+qFD$_J4 zkU}gf27)%GYI2Jp8;8UgXu?5`fleGsiXdoHs-`FgvT>+I4u=Cp(1}Ac>Q$v`?xG$J zN07r|@p9~s`=Sin%Sb7xWHLsJ;C3FmYV6B oizrr;8kQXA0h87DBMYA57nRLV1Xd(_#q%~#*A%UWrp@F25AZ&nn*aa+ delta 7728 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 A1poj5 diff --git a/driver/main b/driver/main index 307f0d11d04d72b7975813db9368b614f6609fe6..1fb9afc02e0ab28b2eda76938758a047b173763e 100755 GIT binary patch delta 12089 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 S*(`Fi>WTx#+V)hJ3;zckh^nUm diff --git a/firmware/B15F.elf b/firmware/B15F.elf index c37872f2a971804f7b4e42f77acf27aba0ef7dee..c153cbd6d3b84ca0b814b710be4a0ccbbeae0adf 100644 GIT binary patch delta 4396 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 + } + cli(); + ((USART*) &usart)->nextByte(UDR0); + sei(); +} + void initAll() { - spi.init(); + ((SPI*) &spi)->init(); - beba0.setDirA(0x00); // alle Ausgang - beba0.setDirB(0xFF); // alle Eingang - beba1.setDirA(0x00); // alle Ausgang - beba1.setDirB(0xFF); // alle Eingang - sw.setDirB(0xFF); // alle Eingang + ((MCP23S17*) &beba0)->setDirA(0x00); // alle Ausgang + ((MCP23S17*) &beba0)->setDirB(0xFF); // alle Eingang + ((MCP23S17*) &beba1)->setDirA(0x00); // alle Ausgang + ((MCP23S17*) &beba1)->setDirB(0xFF); // alle Eingang + ((MCP23S17*) &sw)->setDirB(0xFF); // alle Eingang - adu.init(); - usart.init(); + ((ADU*) &adu)->init(); + ((USART*) &usart)->init(); // aktiviere Interrupts sei(); @@ -35,9 +46,9 @@ void handleRequest() { wdt_disable(); - beba1.writePortA(0xFF); - const uint8_t req = usart.readByte(); - beba1.writePortA(0x00); + ((MCP23S17*) &beba1)->writePortA(0xFF); + const uint8_t req = ((USART*) &usart)->readByte(); + ((MCP23S17*) &beba1)->writePortA(0x00); // starte WDT wdt_enable(WDT_TIMEOUT); @@ -104,16 +115,16 @@ int main() // Reset anzeigen - beba0.writePortA(0xFF); + ((MCP23S17*) &beba0)->writePortA(0xFF); _delay_ms(100); - beba0.writePortA(0x00); + ((MCP23S17*) &beba0)->writePortA(0x00); uint8_t n = 0; uint8_t block[16]; while(1) { - beba0.writePortA(n++ & 0xFF); - usart.readBlock(&block[0], 0); + //testAll(); + _delay_ms(1); } while(1) diff --git a/firmware/requests.cpp b/firmware/requests.cpp index 3ab761b..4d870e7 100644 --- a/firmware/requests.cpp +++ b/firmware/requests.cpp @@ -2,99 +2,99 @@ void rqTestConnection() { - uint8_t dummy = usart.readByte(); - usart.writeByte(USART::MSG_OK); - usart.writeByte(dummy); + uint8_t dummy = ((USART*) &usart)->readByte(); + ((USART*) &usart)->writeByte(USART::MSG_OK); + ((USART*) &usart)->writeByte(dummy); } void rqBoardInfo() { - usart.writeByte(3); // Anzahl an Strings + ((USART*) &usart)->writeByte(3); // Anzahl an Strings - usart.writeStr(DATE, sizeof(DATE)); - usart.writeStr(TIME, sizeof(TIME)); - usart.writeStr(FSRC, sizeof(FSRC)); - usart.writeByte(USART::MSG_OK); + ((USART*) &usart)->writeStr(DATE, sizeof(DATE)); + ((USART*) &usart)->writeStr(TIME, sizeof(TIME)); + ((USART*) &usart)->writeStr(FSRC, sizeof(FSRC)); + ((USART*) &usart)->writeByte(USART::MSG_OK); } void rqTestIntConv() { - usart.writeInt(usart.readInt() * 3); + ((USART*) &usart)->writeInt(((USART*) &usart)->readInt() * 3); } void rqDigitalWrite0() { - uint8_t port = usart.readByte(); - beba0.writePortA(port); + uint8_t port = ((USART*) &usart)->readByte(); + ((MCP23S17*) &beba0)->writePortA(port); - usart.writeByte(USART::MSG_OK); + ((USART*) &usart)->writeByte(USART::MSG_OK); } void rqDigitalWrite1() { - uint8_t port = usart.readByte(); - beba1.writePortA(port); + uint8_t port = ((USART*) &usart)->readByte(); + ((MCP23S17*) &beba1)->writePortA(port); - usart.writeByte(USART::MSG_OK); + ((USART*) &usart)->writeByte(USART::MSG_OK); } void rqDigitalRead0() { - uint8_t port = beba0.readPortB(); - usart.writeByte(port); + uint8_t port = ((MCP23S17*) &beba0)->readPortB(); + ((USART*) &usart)->writeByte(port); } void rqDigitalRead1() { - uint8_t port = beba1.readPortB(); - usart.writeByte(port); + uint8_t port = ((MCP23S17*) &beba1)->readPortB(); + ((USART*) &usart)->writeByte(port); } void rqAnalogWrite0() { - uint16_t value = usart.readInt(); - dac0.setValue(value); + uint16_t value = ((USART*) &usart)->readInt(); + ((TLC5615*) &dac0)->setValue(value); - usart.writeByte(USART::MSG_OK); + ((USART*) &usart)->writeByte(USART::MSG_OK); } void rqAnalogWrite1() { - uint16_t value = usart.readInt(); - dac1.setValue(value); + uint16_t value = ((USART*) &usart)->readInt(); + ((TLC5615*) &dac1)->setValue(value); - usart.writeByte(USART::MSG_OK); + ((USART*) &usart)->writeByte(USART::MSG_OK); } void rqAnalogRead() { - uint8_t channel = usart.readByte(); - uint16_t value = adu.getValue(channel); - usart.writeInt(value); + uint8_t channel = ((USART*) &usart)->readByte(); + uint16_t value = ((ADU*) &adu)->getValue(channel); + ((USART*) &usart)->writeInt(value); } void rqAdcDacStroke() { - uint8_t channel_a = usart.readByte(); - uint8_t channel_b = usart.readByte(); + uint8_t channel_a = ((USART*) &usart)->readByte(); + uint8_t channel_b = ((USART*) &usart)->readByte(); - int16_t start = static_cast(usart.readInt()); - int16_t delta = static_cast(usart.readInt()); - int16_t count = static_cast(usart.readInt()); + int16_t start = static_cast(((USART*) &usart)->readInt()); + int16_t delta = static_cast(((USART*) &usart)->readInt()); + int16_t count = static_cast(((USART*) &usart)->readInt()); - usart.writeByte(USART::MSG_OK); + ((USART*) &usart)->writeByte(USART::MSG_OK); count *= delta; for(int16_t i = start; i < count; i += delta) { - dac0.setValue(i); + ((TLC5615*) &dac0)->setValue(i); wdt_reset(); - uint16_t val_a = adu.getValue(channel_a); - uint16_t val_b = adu.getValue(channel_b); - usart.writeInt(val_a); - usart.writeInt(val_b); + uint16_t val_a = ((ADU*) &adu)->getValue(channel_a); + uint16_t val_b = ((ADU*) &adu)->getValue(channel_b); + ((USART*) &usart)->writeInt(val_a); + ((USART*) &usart)->writeInt(val_b); /*union doubleword { @@ -103,19 +103,19 @@ void rqAdcDacStroke() }; union doubleword dw; - dw.word[0] = adu.getValue(channel_a); - dw.word[1] = adu.getValue(channel_b); + dw.word[0] = ((ADU*) &adu)->getValue(channel_a); + dw.word[1] = ((ADU*) &adu)->getValue(channel_b); uint8_t ret = 0; do { wdt_reset(); - ret = usart.writeBlock(&(dw.byte[0]), 4); + ret = ((USART*) &usart)->writeBlock(&(dw.byte[0]), 4); if(ret == 0) return; } while(ret != USART::MSG_OK);*/ } - usart.writeByte(USART::MSG_OK); + ((USART*) &usart)->writeByte(USART::MSG_OK); } diff --git a/firmware/selftest.cpp b/firmware/selftest.cpp index 2cf7bd2..c75a77d 100644 --- a/firmware/selftest.cpp +++ b/firmware/selftest.cpp @@ -13,7 +13,7 @@ void testBEBA0(void) { for(uint8_t i = 0; i < 9; i++) { - beba0.writePortA(_BV(i)); + ((MCP23S17*) &beba0)->writePortA(_BV(i)); if(i < 8) _delay_ms(200); @@ -24,7 +24,7 @@ void testBEBA1(void) { for(uint8_t i = 0; i < 9; i++) { - beba1.writePortA(_BV(i)); + ((MCP23S17*) &beba1)->writePortA(_BV(i)); if(i < 8) _delay_ms(200); @@ -35,22 +35,22 @@ void testDAC0(void) { for(uint16_t i = 0; i < 1024; i++) { - dac0.setValue(i); + ((TLC5615*) &dac0)->setValue(i); _delay_ms(1); } _delay_ms(100); - dac0.setValue(0); + ((TLC5615*) &dac0)->setValue(0); } void testDAC1(void) { for(uint16_t i = 0; i < 1024; i++) { - dac1.setValue(i); + ((TLC5615*) &dac1)->setValue(i); _delay_ms(1); } _delay_ms(100); - dac1.setValue(0); + ((TLC5615*) &dac1)->setValue(0); } void testMirror() @@ -61,9 +61,9 @@ void testMirror() // Endlosschleife while(1) { - dac0.setValue(adu.getValue(0)); - dac1.setValue(adu.getValue(1)); - beba0.writePortA(beba0.readPortB()); - beba1.writePortA(sw.readPortB()); + ((TLC5615*) &dac0)->setValue(((ADU*) &adu)->getValue(0)); + ((TLC5615*) &dac1)->setValue(((ADU*) &adu)->getValue(1)); + ((MCP23S17*) &beba0)->writePortA(((MCP23S17*) &beba0)->readPortB()); + ((MCP23S17*) &beba1)->writePortA(((MCP23S17*) &sw)->readPortB()); } } diff --git a/firmware/usart.cpp b/firmware/usart.cpp index d03149d..dc78264 100644 --- a/firmware/usart.cpp +++ b/firmware/usart.cpp @@ -4,7 +4,7 @@ void USART::init() { UCSR0A = _BV(U2X0); - UCSR0B = _BV(RXEN0) | _BV(TXEN0); + UCSR0B = _BV(RXEN0) | _BV(TXEN0) | _BV(RXCIE0); // Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit UCSR0C = _BV(UCSZ00) |_BV(UCSZ01);// (1< MAX_BLOCK_SIZE) + { + clearInputBuffer(); + writeByte(MSG_FAIL); + seq = BlockSequence::IDLE; + } + else + { + block_buffer[0] = byte; + crc = 0; + block_pos = 0; + seq = BlockSequence::LEN; + } + break; + } + case LEN: + { + block_buffer[block_pos] = byte; + seq = BlockSequence::DATA; + break; + } + case DATA: + { + block_buffer[block_pos] = byte; + crc ^= byte; + for (uint8_t i = 0; i < 8; i++) + { + if (crc & 1) + crc ^= CRC7_POLY; + crc >>= 1; + } + if(block_pos == block_buffer[0]) + seq = BlockSequence::CRC; + else if(block_pos >= block_buffer[0]) + { + clearInputBuffer(); + writeByte(MSG_FAIL); + seq = BlockSequence::IDLE; + } + break; + } + case CRC: + { + block_buffer[block_pos] = byte; + crc ^= byte; + for (uint8_t i = 0; i < 8; i++) + { + if (crc & 1) + crc ^= CRC7_POLY; + crc >>= 1; + } + seq = BlockSequence::END; + break; + } + case END: + { + clearInputBuffer(); + writeByte(crc == 0 ? MSG_OK : MSG_FAIL); + seq = BlockSequence::IDLE; + break; + } + + + } + block_pos++; +} + void USART::readBlock(uint8_t* ptr, uint8_t offset) { ptr += offset; @@ -129,7 +202,7 @@ void USART::readBlock(uint8_t* ptr, uint8_t offset) } - flush(); // leere Eingangspuffer + clearInputBuffer(); // leere Eingangspuffer writeByte(crc == 0 ? MSG_OK : MSG_FAIL); } diff --git a/firmware/usart.h b/firmware/usart.h index f427f3b..ab5022e 100644 --- a/firmware/usart.h +++ b/firmware/usart.h @@ -5,15 +5,20 @@ #include #include -constexpr uint32_t BAUDRATE = 115200; // 38400 -constexpr uint8_t CRC7_POLY = 0x91; -constexpr uint8_t MAX_BLOCK_SIZE = 16; +enum BlockSequence +{ + IDLE = 0, + LEN = 1, + DATA = 2, + CRC = 3, + END = 4, +}; class USART { public: void init(void); - void flush(void); + void clearInputBuffer(void); void writeByte(uint8_t); void writeInt(uint16_t); @@ -23,10 +28,24 @@ public: uint8_t readByte(void); uint16_t readInt(void); uint32_t readLong(void); + + void nextByte(uint8_t byte); void readBlock(uint8_t*, uint8_t); constexpr static uint8_t MSG_OK = 0xFF; constexpr static uint8_t MSG_FAIL = 0xFE; + + uint8_t block_pos = 0; + + // constants + constexpr static uint32_t BAUDRATE = 115200; // 38400 + constexpr static uint8_t CRC7_POLY = 0x91; + constexpr static uint8_t MAX_BLOCK_SIZE = 64; + constexpr static uint8_t BLOCK_END = 0x80; +private: + uint8_t block_buffer[MAX_BLOCK_SIZE + 3]; // don't store BLOCK_END byte + uint8_t crc; + BlockSequence seq = BlockSequence::IDLE; }; #endif // USART_H