From 041d9d131f1980ffb91da6e8f9cf522950373ea1 Mon Sep 17 00:00:00 2001 From: gregfoss Date: Sat, 19 Oct 2019 17:20:14 -0400 Subject: [PATCH 01/12] Adding simple sensor thread interface --- breadcrumbs/src/io/SensorInterface.cpp | 18 ++++++++++++++++++ breadcrumbs/src/io/SensorInterface.hpp | 22 ++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 breadcrumbs/src/io/SensorInterface.cpp create mode 100644 breadcrumbs/src/io/SensorInterface.hpp diff --git a/breadcrumbs/src/io/SensorInterface.cpp b/breadcrumbs/src/io/SensorInterface.cpp new file mode 100644 index 0000000..f0f0e03 --- /dev/null +++ b/breadcrumbs/src/io/SensorInterface.cpp @@ -0,0 +1,18 @@ + +#include "SensorInterface.hpp" + + +int SensorThread::startThread() +{ + +} + +int SensorThread::stopThread() +{ + +} + +size_t SensorThread::getNewData(char* dataBuffer) +{ + +} diff --git a/breadcrumbs/src/io/SensorInterface.hpp b/breadcrumbs/src/io/SensorInterface.hpp new file mode 100644 index 0000000..7433d82 --- /dev/null +++ b/breadcrumbs/src/io/SensorInterface.hpp @@ -0,0 +1,22 @@ +/* + +Stores the interface for building a sensor thread +implementation. + +*/ + + +class SensorThread +{ +public: + SensorThread(void* targs) { implementationData = targs }; + int startThread(); + int stopThread(); + void* threadRuntime(void* targs) = 0; + int execute_command(char* command) = 0; + size_t getNewData(char* dataBuffer); +private: + char* ab_dataBuffer; + size_t ui_dataBufferSize; + void* implementationData; +}; From 2bf62d70a04bf6a592594a130c77f687854de2b5 Mon Sep 17 00:00:00 2001 From: gregfoss Date: Thu, 31 Oct 2019 14:43:16 -0400 Subject: [PATCH 02/12] [Broken]: For Display purposes only --- breadcrumbs/src/Breadcrumbs.cpp | 21 ++++++- breadcrumbs/src/io/SensorInterface.cpp | 18 ------ breadcrumbs/src/io/SensorInterface.hpp | 57 ++++++++++++++----- .../io/out_procs/VirtualOutputProcessor.cpp | 8 +++ .../io/out_procs/VirtualOutputProcessor.hpp | 11 ++++ 5 files changed, 82 insertions(+), 33 deletions(-) delete mode 100644 breadcrumbs/src/io/SensorInterface.cpp create mode 100644 breadcrumbs/src/io/out_procs/VirtualOutputProcessor.cpp create mode 100644 breadcrumbs/src/io/out_procs/VirtualOutputProcessor.hpp diff --git a/breadcrumbs/src/Breadcrumbs.cpp b/breadcrumbs/src/Breadcrumbs.cpp index 8f4ffc9..61522c4 100644 --- a/breadcrumbs/src/Breadcrumbs.cpp +++ b/breadcrumbs/src/Breadcrumbs.cpp @@ -1,7 +1,26 @@ #include +#include "io/out_procs/VirtualOutputProcessor.hpp" + + +#define THREADS 5 + int main() { - printf("Hello world!\n"); + printf("Hello World!\n"); + + SensorThread* procs[THREADS]; + int targs[THREADS]; + + for (int i = 0; i < THREADS; i++) { + procs[i] = new VirtualOutputProcessor; + targs[i] = i + 1; + procs[i]->startThread(targs + i); + } + + for (int i = 0; i < THREADS; i++) { + procs[i]->waitForThread(); + delete procs[i]; + } return 0; } diff --git a/breadcrumbs/src/io/SensorInterface.cpp b/breadcrumbs/src/io/SensorInterface.cpp deleted file mode 100644 index f0f0e03..0000000 --- a/breadcrumbs/src/io/SensorInterface.cpp +++ /dev/null @@ -1,18 +0,0 @@ - -#include "SensorInterface.hpp" - - -int SensorThread::startThread() -{ - -} - -int SensorThread::stopThread() -{ - -} - -size_t SensorThread::getNewData(char* dataBuffer) -{ - -} diff --git a/breadcrumbs/src/io/SensorInterface.hpp b/breadcrumbs/src/io/SensorInterface.hpp index 7433d82..a5478bf 100644 --- a/breadcrumbs/src/io/SensorInterface.hpp +++ b/breadcrumbs/src/io/SensorInterface.hpp @@ -1,22 +1,51 @@ /* + * + * Stores the interface for building a sensor thread + * implementation. + * + */ -Stores the interface for building a sensor thread -implementation. - -*/ +#include +#include class SensorThread { public: - SensorThread(void* targs) { implementationData = targs }; - int startThread(); - int stopThread(); - void* threadRuntime(void* targs) = 0; - int execute_command(char* command) = 0; - size_t getNewData(char* dataBuffer); -private: - char* ab_dataBuffer; - size_t ui_dataBufferSize; - void* implementationData; + + // Thread start 'caller' function + static DWORD __stdcall threadStart(LPVOID pUserData) { + ((SensorThread*) pUserData)->threadRuntime(); + return 0; + } + // Thread routine for implementation to override + virtual void threadRuntime() = 0; + + // Async control + UINT8 startThread(LPVOID targs)s + { + threadArgs = targs; + hThread = CreateThread( + NULL, // default security attributes + 0, // use default stack size + threadStart, // thread function name + this, // argument to thread function + 0, // use default creation flags + &dwThreadId); // returns the thread identifier + return TRUE; + }; + BOOL waitForThread() + { + WaitForSingleObject(hThread, INFINITE); + return TRUE; + }; + + // Sync control + BOOLEAN bufferDataAvailable() { return TRUE; }; + SIZE_T getBufferData(LPCSTR* bufferKeyArray, LPCSTR* bufferValueArray) { return 0; }; + VOID setDataStoreValue(LPCSTR key, LPCVOID value, SIZE_T valueSize) {}; +protected: + LPCVOID threadArgs; + DWORD dwThreadId; + HANDLE hThread; }; diff --git a/breadcrumbs/src/io/out_procs/VirtualOutputProcessor.cpp b/breadcrumbs/src/io/out_procs/VirtualOutputProcessor.cpp new file mode 100644 index 0000000..1c78bdb --- /dev/null +++ b/breadcrumbs/src/io/out_procs/VirtualOutputProcessor.cpp @@ -0,0 +1,8 @@ + +#include "VirtualOutputProcessor.hpp" + + +void VirtualOutputProcessor::threadRuntime() +{ + printf("Hello from thread %d!\n", *((int*) threadArgs)); +} diff --git a/breadcrumbs/src/io/out_procs/VirtualOutputProcessor.hpp b/breadcrumbs/src/io/out_procs/VirtualOutputProcessor.hpp new file mode 100644 index 0000000..4e283e6 --- /dev/null +++ b/breadcrumbs/src/io/out_procs/VirtualOutputProcessor.hpp @@ -0,0 +1,11 @@ + +#include + +#include "../SensorInterface.hpp" + + +class VirtualOutputProcessor : public SensorThread +{ +public: + virtual void threadRuntime(); +}; From d74d9379bdaac300a951f84614cec57c03add699 Mon Sep 17 00:00:00 2001 From: Matt Scalzo Date: Wed, 4 Mar 2020 18:32:38 -0500 Subject: [PATCH 03/12] Add basic Serial Port Communication This is the preliminary communication code for the Xsens MTi. Right now it can connect to and read a single message from the motion tracker. It then does its best to the print out the message in hex. It still needs some massageing to make it easier to read and usable with all messages. Also, I want to eventually send messages also. I am currently investigaiting different formats the tracker can output/understand. Also also, I added a basic checksum calculator called checksum.cpp. It seems to currently work correctly and I plan on using it to calculate the checksum values for the message I send. --- serialPortComs/checksum.cpp | 17 +++++++ serialPortComs/serial.cpp | 97 +++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 serialPortComs/checksum.cpp create mode 100644 serialPortComs/serial.cpp diff --git a/serialPortComs/checksum.cpp b/serialPortComs/checksum.cpp new file mode 100644 index 0000000..888b083 --- /dev/null +++ b/serialPortComs/checksum.cpp @@ -0,0 +1,17 @@ +#include +using namespace std; + +int main() // Use vector so that it can be trivialy long. +{ + int preamb = 0xFA; + int BID = 0xFF; + int MID = 0x30; + int LEN = 0x00; + + //cout << "Sum of fields: " << hex << (BID + MID + LEN) << endl; + //cout << "Bit mask on last to " + int check = 0x100 - ((BID + MID + LEN) & 0xFF); // This outputs the correct checksum. + + cout << hex << check << endl; + return 0; +} \ No newline at end of file diff --git a/serialPortComs/serial.cpp b/serialPortComs/serial.cpp new file mode 100644 index 0000000..7bb67c2 --- /dev/null +++ b/serialPortComs/serial.cpp @@ -0,0 +1,97 @@ +#include +#include + +int main() +{ + DCB dcb = {0}; + HANDLE hSerial; + + hSerial = CreateFile("COM8", // The COM port to connect to + GENERIC_READ | GENERIC_WRITE, + 0, + 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + 0); + + if (hSerial == INVALID_HANDLE_VALUE) + { + if(GetLastError() == ERROR_FILE_NOT_FOUND) + { + std::cout << "Serial port does not exist." << std::endl; + return 1; // serial port does not exist. + } + std::cout << "Some other error occurred." << std::endl; + return 2; // some other error occurred. + } + + dcb.DCBlength = sizeof(dcb); + + if (!GetCommState(hSerial, &dcb)) + { + std::cout << "Error getting state." << std::endl; + return 3; // error getting state. + } + + dcb.BaudRate = CBR_115200; // defualt baud rate of MT + dcb.ByteSize = 8; + dcb.StopBits = ONESTOPBIT; + dcb.Parity = NOPARITY; + + if (!SetCommState(hSerial, &dcb)) + { + std::cout << "Error setting serial port state." << std::endl; + return 4; // error setting serial port state + } + + COMMTIMEOUTS timeouts = {0}; + + timeouts.ReadIntervalTimeout = 50; + timeouts.ReadTotalTimeoutConstant = 50; + timeouts.ReadTotalTimeoutMultiplier = 10; + timeouts.WriteTotalTimeoutConstant = 50; + timeouts.WriteTotalTimeoutMultiplier = 10; + + if (!SetCommTimeouts(hSerial, &timeouts)) + { + std::cout << "Error occured while setting timoemouts." << std::endl; + return 5; + } + + std::cout << "Connection established!" << std::endl; + std::cout << "Attempting to read data..." << std::endl; + + char szBuff[86 + 1] = {0}; // Buffer size + DWORD dwBytesRead = 0; // Number of bytes actually read + + if (!ReadFile(hSerial, szBuff, 86, &dwBytesRead, NULL)) + { + std::cout << "Error occured while trying to read bytes." << std::endl; + return 6; + } + + std::cout << "Bytes read: " << dwBytesRead << std::endl; + + for (__int8 c : szBuff) + { + std::cout << std::hex << int(c) << std::endl; + } + + std::cout << std::endl; + + std::cout << "Closing Handle..." << std::endl; + CloseHandle(hSerial); + std::cout << "Handle Closed." << std::endl; + + // The above code "works" though it kinda sucks. Bunch of weird + // formatting stuff to do with char/int and cout. It looks likes + // that it is putting in spaces in certain parts that messes with + // trying to get the data out of the buffer. Maybe look into string + // output fromat settings on the device? + + // Next thing to do is work on sending a message in the correct + // format so that it understands, also recieving messages of + // different sizes. Also converting the data I get into readable/ + // usable data that means something to the rest of the program. + +} \ No newline at end of file From eb72ddf4177fe0bab7886f2f2eb322139e95e956 Mon Sep 17 00:00:00 2001 From: Matt Scalzo Date: Thu, 5 Mar 2020 13:26:07 -0500 Subject: [PATCH 04/12] Add Possible Fix for Hex/Char formatting The fix is in checksum.cpp, it has to do with HexCharStruct. Using this seemed to fix my issues with converting from char to hex (int but not really). Next I should try and use this struct in serial.cpp and see if it fixes the issue. I also worked on structuring a message, should it be in a vector? Should it just be a char buffer with spaces in between? Should I instead look into String format instead of binary format on the MT's side? Not really sure... --- serialPortComs/Docs/Serial.pdf | Bin 0 -> 24647 bytes serialPortComs/Docs/serial-win.pdf | Bin 0 -> 65546 bytes serialPortComs/checksum.cpp | 48 ++++++++++++++++++++++++----- serialPortComs/serial.cpp | 5 +-- 4 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 serialPortComs/Docs/Serial.pdf create mode 100644 serialPortComs/Docs/serial-win.pdf diff --git a/serialPortComs/Docs/Serial.pdf b/serialPortComs/Docs/Serial.pdf new file mode 100644 index 0000000000000000000000000000000000000000..670b52f01e805451c03bf312cb832b36da670b84 GIT binary patch literal 24647 zcmeIa2{@Er`#4VaiDU~E4cWI@j2RR`$0s{%%k%$^l7r#ou#QlSJQ6L3L&(d^V{vj$I4B-KMjnI5D3fIj@+D!2q;+{hSwOyVhRcSYIEM7=E0ZI^dWixD^&YCfp%PAG1hx`VA@1q0LnE z(he*=y%u#0qLh<;G{%vh{xCiN^*Fa&K1(7mlw_FE++G^HKxG{f8Q$=PmZsm4ek<4s z@9>C|w!4#=`RI_qRVrE@so+HV+qQ(rh55ZyOg);TVZ*dR(4_9vRwNi)U} zJ$wQB)xF&PJUo4YX#$7|N5GQ2hycyX$`C7C7#R2*f|v(-<0*mzgoMKf*urGNa1;#S z?j}|^I^xN^*nKaOPWB-mOXTBEJRlx$J(buQT41*PjxjE&wIOBc6FhGd_(No4! z$B;1YUd|A5i2=qD@9qmG(`X7YBN6?uBy%DjPthF!5i-;ePr~4UCV-GAd1C?|izn+7 zK%F6m=!VAuCWI_$j4#R13rBDw;BjIa3UDY?4ho0L!(ebY0xqr${QZk6l-_>o7z`kU z2e?fF^v2g4gT({77VEfE=q1w$5K9C~Huzxb zMFNx%3G?P-CJmN!M-v`pb z`(lX%Z?Z1K(d(LJMZl3!#ozg-&J?`3tZXi2$z){ddt* zn7c_8Hs^n48CjfU(UQO9c?#Pkg7tC8_2mKakZY2^WZ?ldf%+7+pr{BLj;08FbMNZ{ zq$mV{%jPFV)Zg&itQutH+l(tYO`#YVpImRFjDp9v_M1oi_tIoczN_bE1)$8hUlicS zjHK8mHL~@RmXnhQOUpu0z={mO0tSU64^c{uFdo2!{s&7yv9PiT;AMdKumr_P$~<&Y5TZ)qq*)fY=PsleI~LLQ!+mWIQS5MAK)LcpqeI=hoCEZOX6VLS-# zfnt;)!GQGvQ_PPzr3^4}coNnHV&p~iz_?RDR_mjopn#$OZt&1#mHW4-1{P|YsfMEd znQHPZ_?cjN`2TP8B7UZqZ1OhI`~5WmF;fLQVcdQ3kORiw5@v>As0Omo~ zD#IevYYDIhF1Niy?#P>pK-?7ZhcEWt?BG%tB^GDp65MdqS&f zFPz@0cM-y)+j{TS3OXY`eroguoKXxTWPR8;-t_Gmupm|uo<$3pvt{RuGC8_RGeU>P zG$twUCippamnpt5=}R(bTp3-6p2wcK(skuoGmd{kw@SE73bHln%FDbf{Y@)vmCxB_ zKdn0Mv@@8c8hk}9Q#4kq+9KpO%0$;ybUB}Q)3lNS-hx z4AR?pAHQ%)RX%r{O>NQ?v}>#``uU-W`6BdrdRW-jwLXSZ{tY)kyBo6^V|_Atjf8}+ zkK3w=;>4^UyOp?U8h0$DS#QyCy_~!gpQVysd*eW|m{hWqbgNM=x)TczG#1FuRxo@z z#|SKC?bx2Y)i&IdRyI%5`y9sC5KgbHc~V)WTumb+df>D^$?t{t-hr~t zU*<_a?l;$$EzHdoc(ihxMpJaN&>L}xUMY>?zT*dWy7ABnF$Y(hhUU{7lsvs)*28Fb z*F$%2Z=#lv%wDcY8JegYg`-xP1wMrt<$4dqnJ*TC=*x3izDP9YT~?KPY_MPWQH+VCRYZRxb9JS?RXa#<{+PV7zWzIP|!6 zY+J&^LMl3O@C_f(DZN*W3+(JtR1wEgIC-w>aeBsAHIDIMA_d-AAa1!i5&Va@`v+D$ za}{Vg9KMua3vRM6Qd5W(jm+Th?C@N6_|R`JdA=~)_KKd(i?11WlR^6fEOei^m@1w) zO&F4f2L{BP+9f*7XrDx+xs0uJi*IH)y%Dq5=ko7clu`#>yVcjE zI4AuYImRQ+QumUn*({eP+dPLiEt&sRhZT=L%e_I@?YDN84`$ogm$ zlS*Gg=ZycphuDT1JPjVz)N>8)5O%tORueA$yfjQ*S*fCwdRn2|m$*>&&V(FZHX2TdKP6^`7W& zry^db=grUKwQ;WALPH}SOnsV1tRWNBqWSgq_>n%o(7Q4Ew?=iIdAX0C7#IH{y69cf z=a4?(k!(I{bpNBP%IfF0o{K)9I-b&L)<_RtE_V58vzC2vW@{W7jT7F|*|o^(&YRMK z?Q)6ECmNEgO)uTfeBkdx%YM?AC#JWhsFYb1roMz2jL)5Z9$E9$+2Gpw`(GJY_=Z1e zNUAam7FAgIsTIkn$h?^}fcAUbQMrA=F4>~|i|2N>Sr(Q;nR9X58lsw{ZFRb??|74* zcf4hnBPiXJ#@5@!Z*rD?me$})h{D!%+h>+1r)UjRR}%vSt2D!(WLIwyo7;1J#_L$$ zE*wLkwn!jz+83{zC%Nx?i#?3%m8V_+S(3UC&7EsA|| zJ5S}-iI?*kI}KDEY__1C&0Fee8EVVRYZ-D-*qM-5Cs6*5*mkM4s$8Os)NdZ9;*$QJ z_sRLdkE`=*Es1*=9?X{|z2=Wj^EsFvoN73$Vi;DN$xyj8dwlw4*^xt_+!u{1yWq2Z zPDAI_FH1c8cu;`#;8cqJP@3W89d?#acf5A!8(qzwItSyfx3~3Px{?rBm-bLLYy892 zi1#Nxx7`+8Y5df+QWZr#7ib@m#vNn2^k&zan5`VatH*W()X@*g6qGBz5jfdj*l}X< z&VBtxZ-$qvrc;J|$=$?!`Q+-*lPrk+ul4nf$2vS|qOMq1B`B(0Ev2?BVvT}1nfq;9 zefA1pc8Nthz_Q?yN!5peVpiIOGlB0JBIeHdkGv1vKUNfHcwX0r`Nei;;fHp6s<14yXt(&XYTo3+f7lh)O zZ(2hAn?ABS;N}zXL|~ozFCApK+`r)~ksT3Jz$K?R$Vgx%PX2Cu*3+AzKSMT3)}iE9 zKbLRLulKpR#XqGt`uVkdy|-VXoAVoZZytAZ`JdAN-0MG={HY%R_LCn(-crNU136@3y+jA%=9M~9y0~>;5HKn*{e^kVu z-4z(H(fh+clS9jX_s@`xffI{_ud8hIF?jm`UaAVi; z`%dHkc6V{JzxaJ(ZFq|aU@P$V{rk<{VuIBnuW{s#kfoB*oV$FoU%I)CIbFIZvkx&3 zX6}5We$`qGnHeyq!>j8lvNE+~Z@TBKAuLEIJJo7p#5W)S60)%G^V&-K0sp!$8a$uJ zjt^zcw4ONA!X>JG^Y-V7J#){BJu8dSr_Zw)RWMi&&w!7tfa+Q+1Tw~+e;w17Ya3&Y ze2(5L&W$i?T@2(p^Kr4RC~>H_<-oB}S*MpF_jR{$M>0uph`a|Uq&Ci7H)`k6ztPX4 z{9dRfts44fj$t%eYD(`e!`w+7EWbwj|3OxlFSqWo(*@uPJif)I;gS)`B`o&ODMi^15HS#_S-q zWn(N&=yGi`JgxNl>o@uzKJ4RM#(PjLFE?np#9GoIZXa zTF-+}ch-i_E|54zZyjx_?vxa5RyY1?u2Y)w+odWi^p1(&DYY=K50^2@t5mHl*!p_s zsSl`(%P^yK=6FIHG&e%Yz)&E%r|G&;aXfz>?<=OV(V-XAip{WlntRUXfOl(9aq0#t zXAH!C2~e;odF|)B->qkKn}w2x4asz^kE`o)@M(F>*3mNMDugh+S2 zqG2F=aU$jY37hcUS4{R^cw{~(nx$nFKE6+IUjJ;TKIdXVI{xf*A~(x4=fSonwwST4 z885YF3)u&o__r;Z>s{o1o5PuL|8>igfLju0FHKg>^mK29x*jWvq<^>~%XUhypb~9; z$nmU>30Dhj>9(HUJFWn=G5P1ip=+!Y?$`0S5e@FbcttL={*_h-2{A`4T&|0&ynSnb ziMs5C-U-(S;__j6qee7UZ{|A7=Zt9Doa9E`s~I_->34?j%Gr`?{WRgKxU&B{kFO1k z3k9dq`82Sju|Cm^R0HOUmnH7?8?i{w=G1wh!#y zmq2?TRoF|?lRVHC=UOt=87%H?A1`F1x>>-JXY+}%OQY)LDov=YeYVhpaqG{gN+X_E zY-QE9ro~z6TO?H-mU+0Z7!DT62TwG3_qqFLQJu6fFW z@GLA|LpmDdazUz(s8OS~yLAzzRdU`5&BTcQS{r>p)1NMFVbU(DqhH1CIwIB%#e4S%d@=>_^;4tR;aGbuXf6((=r663~^K|{oVkzZeG9DRT1onLRtcQ;7 z$e|q`do046AUhsNz8PtZu8G;Lu|2bFb$Ls$hz}Y(FBSCw{Qf#`7xLHz#*|xO#)p{N zE(;$>XkVx|W{;0a>Lo@TJ*jZ|!EG=9P&8&>SqVG=w5Wd|EaWm!y**{Qv7q@9D)Hf2 zo7M~Q_meDqqk#TnBiLTMGr5hvI~Kc^A`P9Iu0hv)Thm89ow6^d1SSOBV><0%YB3osJ_V3nns7R*$%}LHES-YYE<0>g zMO*vwX%0n$KJ`Z3lEQUdNRjq#&p^H{dj;^ePbKD(YF7e(|IzjqH_-{7ONZNq%NX>c zJ8C1R8c1UCqkY00Y{w@KY`^z9ZpBUOQEs@HRTMr)M?yz>IJrx6hx{_JP3moV=Kf#@ zhC!HN_W&lUh71o}5W{|qk= z#VH|)r@Q!X(Gjvnvu-P>C^zJY_^-bylCbKan`>?>MTTOZPoHT?HL1rYcyPX%7U-Dl zuMjo7SadLX*vv;^^1TnAcIu4k>KYO4heKS9UDA`K6?QjYdw8rB2BTR zj1k6qYc1$0J~${+AwKCYziob%OgsJFQ-;39dT%*1cG|$xUWP>DR<2Oz*JqiT@#1pS zm`;z!I|`)~2U zr49UC{B+au-X0wscfIDr{o$Chr+j6yWUlKYeyBuQ@Fk)l)8|htD4x$X_2(IhikT1R zbZLmUb}oIK+1H;o8=F!N{j@9H!SvIZ-ORz$1D4G6;Up11rKgjhnibV^6NpSaAvf;v zgQ$)_p(`!H9F~-Na+bAsPki#n=i8*qMYH^F)P=aol}1eaN<3^iv2gu`^5Z93N?Xvy z7Efd!xftp&g}Hv>;VGZEt#Q&ophD3)itmjq5oyYiSuN7+x}TaDW9-SqD`MdRlM&X! zvXp4k+F_1r9_h8u=`ikTgXxZ?8u&+rL^_?=2NN3Nr8#F2FH&evV%oVygr2xd-rYj6 z`^Lox-&A3phn7(y&8Mi-5dpWvS_(6+?Pz4zqesSo+y@~HHzAiEFx&KsscTE-`5e9B z9H4bZ-Ku_#<_XKaNNUW1BUgRLWNIUB@ad<@Mm&%14sQ;jt#N#}UwC)&-a$jFi3)*| ze%77CYMJ!+`l433eGX%f575xU_vLXknD20(eOuG?|*YW z`(IhZ0tYKLelQ}F@zXCJz$qcQf3b$m0M@WWNKWz^)_%(_9hcB}jr1)yt_kzAx0K#O z-hb+YiS{2u%=ciR> zQKiOPOK=YR-yZ92yZ1p+gZX2&iUQ^d6XeptuNSDLdEapfRhV*}fp&6XL>N9|V4{}i zj?$U(#uNyePMj|Ci*eGuyZdNc($tLi#oVHg+KAyR178Geiao7#gN7G+Up>6tdoay0 zCw8QFdFc4w4Ef!@G+{^HS+pK|vEO8;b?funE{NTi__?DiSY|LYVUwZcxr$FXyl|zqGr@u7n%vuq zNwe(A!q%|+hL1I7#U{dzzRBRsPU=aq%^7^6n!{K~)Pa0PS`=7X$B22sW{*#9^ ztwZ{E;)Y{R#~hDm} zbSQ}0J}q6TU<#)x65L`>7>Iw3wC6hMYR#+*DxVsWoV6cc%;;%Oaw#rnBrVLmLYm!q zAN|c1*b9;6X6qbs7ouUJ;<(5@=&5T%f_WVp^PWQ8gHwT zXqmW`?O4EBPDr4^IO$vn^^W9@$u{@hHI+D?p}jXoE*&3svj<)C0S8bynx@rVfp#HT zX@*8&w=<#^-VhadwD)7PXfetd606RlGCHSZUTKBLA_&S?=VleMnq=q;^W(EqpJ?7)x?Ns;iisd7DxFf&b)a+ebci?jYh4fylOs5)zd^5Ji4+&VD^QD z5u|gzZhl{Y4^mMBr|r`+$F#;e?AZ;{grNMN^xo?{*R16tlWx__XI9H~hMnOw*R6ai zfx~r*tJ#qgcxtwl6@sCdjL>-CNac3+J3No!)Ip>dBfF=Tn_c27H>M27C8%V&yTcvoHF+NN?{J`*WF9K2_sM3YXZ z-R1UkPm_5bx#we1`>rW^u!YlHkbG3=A5b|U;yfP|Xmu6a)L>BMTNLpyq24sf^nUQ= z{v&N%Gt5O@CkWxyLK1aYzpo#O9`Z~UkGF&u2;E1d**r-KpQ#^J!-tPz&TuwV9AM}U z+rmuMr@W)@57zz12HD0jJOprh?RP(Z{an}qM_1tNAW#gP1p-bG$^(Zxf$gOqK7PR9 zy9>jfL-O0B4@Y}}S-vuHQV)`703dhu_VWmZ`-D6d* z{Fry(e&ap5qdX26t?39j1abGPzKm0CVbiwz&qcY%hk-?AQ=k* zsc9a4+_)t|`h(JoUFzCLVfBKwJU3{YxjEe1MVzGQ(oa3Q+jP93CFu&PUvIWScQnwO zJ%BpHJOyO51rm{5A8+lv1)?eh4r#nM-YpPB580c_Y_EEh_in^J)!UDj9N%^axm#{4 zr3+=Vjr7~=7vTVRc4uqu^eggC?#33K-mU4tM!L~|GtF%@(7mzBuXWcIJ;wegTkQ9L zp}YIW&8YE(qe1jbSJN%2+fRa1js2@cyjrcZz|!ifj(WX$&1r4ayJY-CUKr-fGTA=w z<9(O=Ng>j3$1~N^_{V~EwA>o;(I*_Trkv`6dau>Z9{2Q9%uwFbcO3Jne2DMP)bhIz zug&}e>jIB{2`MXKHQ@_;wmW9}ja63OWarA*(0tG*PrD_8ze)mk?pvZy_#M0F*82qC zs%xgZ$a)ZVuo{)Axe@rTbLie9otM!M5Q-ef1Dnb*PoacV zSp!}tW{#N8jU-G3)FxHZfXfNQ5gpiwz?_HbrtURhb7JI(`rPor;RqC+y32sYiJl`e z(8nnL3~?v~Vfe+f_gYL>%lzfwx_yf7GdG+Mbd9a_G>sb`PJb?TbUJi=+tWoWbWYFl zp7}M;_`=fX?srrw4#zb0l)~;L4)07{NguA9nI2Xd?!_!X%l*an3=R7n+hZR(6dJg* zcx~`fx7~1v5?{>BaD||#*%WKZe6Y>*o#m^wc0R99$QJd4$}5H{KbuaJ&gh-&YMTqF zS_$sYls_8WKMg?zkBq%|Va2vwEl3Jp*i*PYp3aRTg1Wqs2(xVos$|l znJCxf!j96&6`Y3+Y3<{}3=*jtuo^2n95d?(#CE!CnQNdQXVBo)3dpgecdWooIe zgLcx@XsMQ%JaXgwP`EAMWG?q(Ty{`6?#3pPcxDc~qI~q7!aANvE%tTF|rbylCD?Jj)DbX3X zmdlG@7Wd`h#ho80OS_?`76~>THg^&`4nABCv3p8Z$EDi>N={Hl224qn>%+H-P8tDZI;goVmQxQmb8!rnOQvTn3S)h>XFAMTvR`O|N@VE1>KaMcJvuQXr zgxtQ$#Xl6Uxec8mu${KGLWxs6%>jkNvJMpw$-Ef6=M;|&dyazN;}X=-VWl?TPw#H> zr030pyJIv0$G2zt3kan!G8_>Y-*t2E9v@C^@zMNKS4OSvn(e@|f;8F<_qOalqt7OP zLIyu7hF*-pwzPQ<+}LSkC(=~V;a>HENG%g2$|m2uoi0(w2*&M5N}E=!9u20dRUYCS zxahb&IAJhhCx5;5JNWe>e1)ujIGxJ*93cnxR-GHX8TrGm2n%oRo6n|$)ZW`eGfyiC zH*qq9oci~j*pWa(AHidAipPI6oX7f_{ADM1o{AR(%z~1Qkz45_jup!UA&-a^SAy{7 z=c$-^b5CBSexJz3%8Yh&=xu8&3_Bxn^VKQ$99&auyz9BH*y2mu!P@4U`(K{F%f%P1 zGeYFf*J9iuly(#uiQKQj%o7=LEa}h-_g;2pDgQa6Bo;F}(IB83hh&2%o zQ%A3ANri}Js7oA=JH685jwsqo>{|*IX7JrFbHQXNj7ax+pANUJX-GU1z$`F zzOY}0p`!*zy0DXedPkenBd;2ROG(M7XeEX1yr)@#b6iHT=jagE=F7CwRdLC2ih?Or z4}9`c4c=@OtvJ|P#9`XRSq>dcj`#=%?Pru=+8VzFjk&V&LUU=STWsm*^*dIuS#7*-16V zC)Fm!cN^w|_6vOGkA9Y7Y;NL1jnC$7N7$-;J^|7ft0}Ftx82_sUGouG*h#pa3Az4m zL2$)xU_x`zZU9J`59Dbs7Ti1#{|<}a!#&W_t}IjPpUXVV=eBbm%_2ebWd)=yiaeUT zb6jfe0X~HEJTnm$Hj-)g=6YAyVXcorhp0m!bqdN~j=a6Tt?uF;*5TgI^J{Yf3m+x} z`onyEm6e}`?b{uyoVBf~&4ca*(?rYa$n5^v_cg1H$pVdcp6?k6ljlVsc)6%$2AMI3m8@ixb|xfnLi5aN`GLbD&Z&uVt?Tfcz5A-pwq>gJ1+<1 z)s=a&n0%YXc-o8`=LU=mpjILud|_w8MV*N%!O5~0IWDw!q!|{}tB?AEg-_gH0U4Z4 z$g79moPS4a+raoj0t(8me?t>_N+|&}W^jLL7rd#JN;Z{)iKkN>_}Z{LLnnk}pjO-P z(A1*Xe5%(kN`t9<bbMl zIBGXg4Bu@!I8QdMITm6IrkN?)pI9ZTPZz_Pnu$5j@5HL!9ktl07ON+(BP*L4i2z5U zak?CxCaE{}pT5HMnh`$9C@M;bK(ELBJK}OEp`kJe#)ACf(t^;4jy-^@Ql#Lq{G&1cCD;=?11#% zH)O!`f4!#gwb>`obZW7D^j2kW)|Z1}*)?lxOOs!h^qvnV&ANtNIB36IrCc+=vJm8% zA(q;Guv#{F;7FE;{u!t{=QHICrd-woc+oQ_nll)ue6p<`+Vn!8Yf1 zkJbNSD*lMLGV=5A1wwNuku;l5SCI4TdwXUOjUQWnlpv>dIB<{wIF2q0(I?=5pcG1o zkSP#u1)SFaleaugzlB|qH#h-9Ui4yo}(@+*Ii(dDRH^QL4p9`@zH2C2gE2;zl z@kwrY64(*%Oz>0^oxM{h3MSx`M6Kiup@!b-co%|B5D{+{WMqyFa>Jr=qAJQDMHLJX zBZ-#|z<5hLQKI8~!N5s+B|&vl11&)nAihp9Kq0`x+XD!}0ta}wd-^H_D2YfSB8R=4A#p7La>IwWT24mBW;8x5WGCWkA3NCmI&K(FAR;K8d8Qy0-;ZFF*;qM7b5#&z||J#xP=GdRf0t(g%0s|=p zbs+o{h-)(krqK@#0)q7nF>dP$1a<-2K zSL1gzg00WgU-am=X8&y^!ePI&!rPDNPBD}?EClb4CsXYU=n)Ly1rDnKD2WFKuyPo0 zZy**5LjuTx0M-d06(}STNbcXJimE$lW2%tNs)9Sl(^*M0KpKa4!uYw9M3pUkfp|_Z z$psHK!xIS@cd)S+5eRT4c!DhnzJ5SnT~hKF-cb64{1^vFVb`_#cfP7&h{Qm!nhaQt zh!6awpY^%AxiygX^>cK^W4|H&FDLru27i(b1qQr|$d(N9{Z$9#e!Vo{zmfkt$bZDu zzwG+UuK$Pw|54??+Vz)R{}BiNqso7^>;Elw0iN-OKMnkxpd{)Kc*}p-D4<+uv+l10 z>u~a7`L~NlfK|09umBea?(_f__P{di549+3@AX>d$@e(@xMAoU42k*;h6bF@U+bX}=e$$P=e4(hzU%mir_|bNXxjy*)rg?b;u(iDT!gm-9xG??O HmGA!t=WM%? literal 0 HcmV?d00001 diff --git a/serialPortComs/Docs/serial-win.pdf b/serialPortComs/Docs/serial-win.pdf new file mode 100644 index 0000000000000000000000000000000000000000..07c96ae49a08e42e8f476d1f6faab27d28c0b2c7 GIT binary patch literal 65546 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 z�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Ů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 +#include using namespace std; +struct HexCharStruct // Fixes char to hex stuff? +{ + unsigned char c; + HexCharStruct(unsigned char _c) : c(_c) { } +}; + +inline ostream& operator<<(ostream& o, const HexCharStruct& hs) +{ + return (o << hex << (int)hs.c); +} + +inline HexCharStruct hex(unsigned char _c) +{ + return HexCharStruct(_c); +} + + int main() // Use vector so that it can be trivialy long. { - int preamb = 0xFA; - int BID = 0xFF; - int MID = 0x30; - int LEN = 0x00; + char preamb = 0xFA; + char BID = 0xFF; + char MID = 0x30; + char LEN = 0x00; + + char check = 0x100 - ((BID + MID + LEN) & 0xFF); // This outputs the correct checksum. + + //cout << hex << check << endl; + cout << hex(check) << endl; + + vector msg; + + msg.push_back(preamb); + msg.push_back(BID); + msg.push_back(MID); + msg.push_back(LEN); + // Data chars would go here + msg.push_back(check); + + for (char c: msg) // Could instead be adding these to the buffer? + cout << hex(c); - //cout << "Sum of fields: " << hex << (BID + MID + LEN) << endl; - //cout << "Bit mask on last to " - int check = 0x100 - ((BID + MID + LEN) & 0xFF); // This outputs the correct checksum. + cout << endl; - cout << hex << check << endl; return 0; } \ No newline at end of file diff --git a/serialPortComs/serial.cpp b/serialPortComs/serial.cpp index 7bb67c2..17da0e8 100644 --- a/serialPortComs/serial.cpp +++ b/serialPortComs/serial.cpp @@ -72,7 +72,7 @@ int main() std::cout << "Bytes read: " << dwBytesRead << std::endl; - for (__int8 c : szBuff) + for (__int8 c : szBuff) // Go into checksum.cpp and try using the HexCharStruct, should fix this. { std::cout << std::hex << int(c) << std::endl; } @@ -87,7 +87,8 @@ int main() // formatting stuff to do with char/int and cout. It looks likes // that it is putting in spaces in certain parts that messes with // trying to get the data out of the buffer. Maybe look into string - // output fromat settings on the device? + // output fromat settings on the device? (right now its using binary) + // **Look in checksum.cpp with the HexCharStrutct.** // Next thing to do is work on sending a message in the correct // format so that it understands, also recieving messages of From 56606fd2e5adbaf6f2f7efe30ed827c803741fdb Mon Sep 17 00:00:00 2001 From: mfs16101 Date: Tue, 10 Mar 2020 13:33:27 -0400 Subject: [PATCH 05/12] Add calChecksum() function Added a function that takes in an abritrarily long vector of chars and calculates the checksum for that message. This hopefully allows for the autimatic calculation of checksum and message construction in order to send messages to the MT. --- serialPortComs/checksum.cpp | 49 +++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/serialPortComs/checksum.cpp b/serialPortComs/checksum.cpp index 3e81987..af8c695 100644 --- a/serialPortComs/checksum.cpp +++ b/serialPortComs/checksum.cpp @@ -18,30 +18,47 @@ inline HexCharStruct hex(unsigned char _c) return HexCharStruct(_c); } +unsigned char calChecksum(const vector msg) +{ + unsigned char sum = 0; + + for (int i=1; i < msg.size(); i++) + { + sum += msg[i]; + } + + unsigned char check = 0x100 - (sum & 0xFF); + + return check; +} + int main() // Use vector so that it can be trivialy long. { - char preamb = 0xFA; - char BID = 0xFF; - char MID = 0x30; - char LEN = 0x00; + unsigned char preamb = 0xFA; + unsigned char BID = 0xFF; + unsigned char MID = 0x30; + unsigned char LEN = 0x00; - char check = 0x100 - ((BID + MID + LEN) & 0xFF); // This outputs the correct checksum. + //unsigned char check1 = 0x100 - ((BID + MID + LEN) & 0xFF); // This outputs the correct checksum. - //cout << hex << check << endl; - cout << hex(check) << endl; + vector mess; - vector msg; - - msg.push_back(preamb); - msg.push_back(BID); - msg.push_back(MID); - msg.push_back(LEN); + mess.push_back(preamb); + mess.push_back(BID); + mess.push_back(MID); + mess.push_back(LEN); // Data chars would go here - msg.push_back(check); - for (char c: msg) // Could instead be adding these to the buffer? - cout << hex(c); + unsigned char check = calChecksum(mess); + + //cout << "Checksum is: " << hex(check) << endl; + mess.push_back(check); + + cout << "GoToConfig message: "; + + for (unsigned char c: mess) // Could instead be adding these to the buffer + cout << hex(c) << " "; cout << endl; From ce5067fe72797c0f3f4bd1337be3904e17f07aa9 Mon Sep 17 00:00:00 2001 From: Matt Scalzo Date: Wed, 11 Mar 2020 16:51:55 -0400 Subject: [PATCH 06/12] Add correct hex formmating to serial.cpp Using the struct in checksum.cpp serial.cpp is now able to print out the chars correctly for humans (except for leading 0s). The next step is to send a message to the MT and also generalize reading output, right now it requires "knowing" the number of bytes it will be reading, I guess this should be already know because of how you program it. The messages I will be constructing will be GoToConfig, SetOutputConfiguration, and GoToMeasurement. I also would like to investigate the String output mode on the device because it seems like it might make the whole char converting uneeded. I also need to work on a translator that can translate the hex code into the actual values we want to read... --- .gitignore | 3 +++ serialPortComs/checksum.cpp | 44 ++++++++++++++++++------------------- serialPortComs/serial.cpp | 44 ++++++++++++++++++++++--------------- 3 files changed, 51 insertions(+), 40 deletions(-) diff --git a/.gitignore b/.gitignore index 346c329..70b4c79 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ .vs/* +# These can be removed when xsensCom branch is merged/removed +*.exe +.vscode/* # Excluding the build and executable folders bfs/build/* diff --git a/serialPortComs/checksum.cpp b/serialPortComs/checksum.cpp index af8c695..27f7233 100644 --- a/serialPortComs/checksum.cpp +++ b/serialPortComs/checksum.cpp @@ -33,34 +33,34 @@ unsigned char calChecksum(const vector msg) } -int main() // Use vector so that it can be trivialy long. -{ - unsigned char preamb = 0xFA; - unsigned char BID = 0xFF; - unsigned char MID = 0x30; - unsigned char LEN = 0x00; +// int main() // Use vector so that it can be trivialy long. +// { +// unsigned char preamb = 0xFA; +// unsigned char BID = 0xFF; +// unsigned char MID = 0x30; +// unsigned char LEN = 0x00; - //unsigned char check1 = 0x100 - ((BID + MID + LEN) & 0xFF); // This outputs the correct checksum. +// //unsigned char check1 = 0x100 - ((BID + MID + LEN) & 0xFF); // This outputs the correct checksum. - vector mess; +// vector mess; - mess.push_back(preamb); - mess.push_back(BID); - mess.push_back(MID); - mess.push_back(LEN); - // Data chars would go here +// mess.push_back(preamb); +// mess.push_back(BID); +// mess.push_back(MID); +// mess.push_back(LEN); +// // Data chars would go here - unsigned char check = calChecksum(mess); +// unsigned char check = calChecksum(mess); - //cout << "Checksum is: " << hex(check) << endl; - mess.push_back(check); +// //cout << "Checksum is: " << hex(check) << endl; +// mess.push_back(check); - cout << "GoToConfig message: "; +// cout << "GoToConfig message: "; - for (unsigned char c: mess) // Could instead be adding these to the buffer - cout << hex(c) << " "; +// for (unsigned char c: mess) // Could instead be adding these to the buffer +// cout << hex(c) << " "; - cout << endl; +// cout << endl; - return 0; -} \ No newline at end of file +// return 0; +// } \ No newline at end of file diff --git a/serialPortComs/serial.cpp b/serialPortComs/serial.cpp index 17da0e8..8a05707 100644 --- a/serialPortComs/serial.cpp +++ b/serialPortComs/serial.cpp @@ -1,5 +1,6 @@ #include #include +#include "checksum.cpp" int main() { @@ -61,34 +62,41 @@ int main() std::cout << "Connection established!" << std::endl; std::cout << "Attempting to read data..." << std::endl; - char szBuff[86 + 1] = {0}; // Buffer size - DWORD dwBytesRead = 0; // Number of bytes actually read + int msgsToRead = 10; + int msgsRead = 0; - if (!ReadFile(hSerial, szBuff, 86, &dwBytesRead, NULL)) + while (msgsRead < msgsToRead) { - std::cout << "Error occured while trying to read bytes." << std::endl; - return 6; - } + std::cout << "Reading message number " << msgsRead + 1 << " out of " << msgsToRead << std::endl; - std::cout << "Bytes read: " << dwBytesRead << std::endl; + unsigned char szBuff[43 + 1] = {0}; // Buffer size + DWORD dwBytesRead = 0; // Number of bytes actually read - for (__int8 c : szBuff) // Go into checksum.cpp and try using the HexCharStruct, should fix this. - { - std::cout << std::hex << int(c) << std::endl; + if (!ReadFile(hSerial, szBuff, 43, &dwBytesRead, NULL)) + { + std::cout << "Error occured while trying to read bytes." << std::endl; + return 6; + } + + std::cout << "Bytes read: " << dwBytesRead << std::endl; + + for (unsigned char c : szBuff) // Using hex() in HexCharStruct from checksum.cpp + { + std::cout << hex(c) << " "; + } + std::cout << std::dec << std::endl; // Pretty sure this resets it back to decimal + + msgsRead++; } - - std::cout << std::endl; std::cout << "Closing Handle..." << std::endl; CloseHandle(hSerial); std::cout << "Handle Closed." << std::endl; - // The above code "works" though it kinda sucks. Bunch of weird - // formatting stuff to do with char/int and cout. It looks likes - // that it is putting in spaces in certain parts that messes with - // trying to get the data out of the buffer. Maybe look into string - // output fromat settings on the device? (right now its using binary) - // **Look in checksum.cpp with the HexCharStrutct.** + // It now reads the data fine, the only problem is leading zeros are + // removed, though they are implied/trivial to add back if I convert to + // string. + // Currently it reads 10 messeges of size 43 bytes then stops. // Next thing to do is work on sending a message in the correct // format so that it understands, also recieving messages of From d742a0ebab04f0bd8ff3b4f5e369e991b9b261e5 Mon Sep 17 00:00:00 2001 From: Matt Scalzo Date: Wed, 1 Apr 2020 15:23:33 -0400 Subject: [PATCH 07/12] Remove debug couts --- serialPortComs/serial.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/serialPortComs/serial.cpp b/serialPortComs/serial.cpp index 8a05707..eec906b 100644 --- a/serialPortComs/serial.cpp +++ b/serialPortComs/serial.cpp @@ -67,7 +67,7 @@ int main() while (msgsRead < msgsToRead) { - std::cout << "Reading message number " << msgsRead + 1 << " out of " << msgsToRead << std::endl; + //std::cout << "Reading message number " << msgsRead + 1 << " out of " << msgsToRead << std::endl; unsigned char szBuff[43 + 1] = {0}; // Buffer size DWORD dwBytesRead = 0; // Number of bytes actually read @@ -78,7 +78,7 @@ int main() return 6; } - std::cout << "Bytes read: " << dwBytesRead << std::endl; + //std::cout << "Bytes read: " << dwBytesRead << std::endl; for (unsigned char c : szBuff) // Using hex() in HexCharStruct from checksum.cpp { From 078ad70e7b42ad3be7780d537e5ee3e39acabc1e Mon Sep 17 00:00:00 2001 From: Matt Scalzo Date: Sun, 12 Apr 2020 23:34:25 -0400 Subject: [PATCH 08/12] Add double conversion test I believe I have gotten the conversion working. I am able to translate the Euler Angles. What I need to do now is develop a better way of captureing full messages from the MT. I have a plan for that, I'm going to capute a large amount of bytes, look for where a message starts, and then go to the correct index to get the data we want. Yeah... --- serialPortComs/doubleConv.cpp | 12 +++++++++++ serialPortComs/serial.cpp | 40 ++++++++++++++++++++++++++++++----- 2 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 serialPortComs/doubleConv.cpp diff --git a/serialPortComs/doubleConv.cpp b/serialPortComs/doubleConv.cpp new file mode 100644 index 0000000..b551201 --- /dev/null +++ b/serialPortComs/doubleConv.cpp @@ -0,0 +1,12 @@ +#include + +using namespace std; + +int main() +{ + unsigned char array[] = {0x00, 0x00, 0x00, 0x20, 0xDB, 0xE2, 0xC4, 0x3F}; //0x3F, 0xC4, 0xE2, 0xDB, 0x20, 0x00, 0x00, 0x00 + + double doubleVal = *reinterpret_cast(array); + + cout << doubleVal << endl; +} diff --git a/serialPortComs/serial.cpp b/serialPortComs/serial.cpp index eec906b..a732045 100644 --- a/serialPortComs/serial.cpp +++ b/serialPortComs/serial.cpp @@ -60,29 +60,59 @@ int main() } std::cout << "Connection established!" << std::endl; + std::cout << "Setting up Config..." << std::endl; + + unsigned char wBuff1[] = {0xFA,0xFF,0x30,0x00,0xD1}; // This is the GoToConfig message + DWORD dwBytesWritten = 0; // Number of bytes actually written + + if (!WriteFile(hSerial, wBuff1, 6, &dwBytesWritten, NULL)) + { + std::cout << "Error occured while trying to send GoToConfig message." << std::endl; + return 6; + } + + unsigned char wBuff2[] = {0xFA,0xFF,0xC0,0x04,0x20,0x33,0x00,0x00,0xEA}; // This is the SetOutputConfiguration message + dwBytesWritten = 0; + + if (!WriteFile(hSerial, wBuff2, 10, &dwBytesWritten, NULL)) + { + std::cout << "Error occured while trying to send SetOutputConfiguration message." << std::endl; + return 7; + } + + unsigned char wBuff3[] = {0xFA,0xFF,0x10,0x00,0xF1}; // This is the GoToMeasurment message + dwBytesWritten = 0; + + if (!WriteFile(hSerial, wBuff3, 6, &dwBytesWritten, NULL)) + { + std::cout << "Error occured while trying to send GoToMeasurment message." << std::endl; + return 8; + } + std::cout << "Attempting to read data..." << std::endl; - int msgsToRead = 10; + int msgsToRead = 2; int msgsRead = 0; while (msgsRead < msgsToRead) { //std::cout << "Reading message number " << msgsRead + 1 << " out of " << msgsToRead << std::endl; - unsigned char szBuff[43 + 1] = {0}; // Buffer size + unsigned char szBuff[128 + 1] = {0}; // Buffer size DWORD dwBytesRead = 0; // Number of bytes actually read - if (!ReadFile(hSerial, szBuff, 43, &dwBytesRead, NULL)) + if (!ReadFile(hSerial, szBuff, 128, &dwBytesRead, NULL)) { std::cout << "Error occured while trying to read bytes." << std::endl; - return 6; + return 9; } //std::cout << "Bytes read: " << dwBytesRead << std::endl; for (unsigned char c : szBuff) // Using hex() in HexCharStruct from checksum.cpp { - std::cout << hex(c) << " "; + std::cout << "INT version:" << std::dec << (int)c << " " << std::endl; + std::cout << "HEX version:" << hex(c) << " " << std::endl;; } std::cout << std::dec << std::endl; // Pretty sure this resets it back to decimal From 1769611c7b919cb27feac130bf1e3d8e21f53467 Mon Sep 17 00:00:00 2001 From: Matt Scalzo Date: Wed, 22 Apr 2020 15:57:52 -0400 Subject: [PATCH 09/12] Updated Comments --- serialPortComs/serial.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/serialPortComs/serial.cpp b/serialPortComs/serial.cpp index a732045..3e845ea 100644 --- a/serialPortComs/serial.cpp +++ b/serialPortComs/serial.cpp @@ -123,14 +123,10 @@ int main() CloseHandle(hSerial); std::cout << "Handle Closed." << std::endl; - // It now reads the data fine, the only problem is leading zeros are - // removed, though they are implied/trivial to add back if I convert to - // string. - // Currently it reads 10 messeges of size 43 bytes then stops. - - // Next thing to do is work on sending a message in the correct - // format so that it understands, also recieving messages of - // different sizes. Also converting the data I get into readable/ - // usable data that means something to the rest of the program. + // Right now I just need a way to search through a large buffer read for message I want + // Should be pretty trivial with a large read and then search for the first starting + // bytes. -} \ No newline at end of file + // Once find a full message, just go to correct index and copy bytes I need. + +} From db6d035821e3e927b6d54e00c41413ea13718822 Mon Sep 17 00:00:00 2001 From: Matt Scalzo Date: Fri, 8 May 2020 00:13:54 -0400 Subject: [PATCH 10/12] Edit to serial.cpp --- serialPortComs/serial.cpp | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/serialPortComs/serial.cpp b/serialPortComs/serial.cpp index a732045..502c43d 100644 --- a/serialPortComs/serial.cpp +++ b/serialPortComs/serial.cpp @@ -91,17 +91,17 @@ int main() std::cout << "Attempting to read data..." << std::endl; - int msgsToRead = 2; + int msgsToRead = 10; int msgsRead = 0; while (msgsRead < msgsToRead) { //std::cout << "Reading message number " << msgsRead + 1 << " out of " << msgsToRead << std::endl; - unsigned char szBuff[128 + 1] = {0}; // Buffer size + unsigned char szBuff[64 + 1] = {0}; // Buffer size DWORD dwBytesRead = 0; // Number of bytes actually read - if (!ReadFile(hSerial, szBuff, 128, &dwBytesRead, NULL)) + if (!ReadFile(hSerial, szBuff, 64, &dwBytesRead, NULL)) { std::cout << "Error occured while trying to read bytes." << std::endl; return 9; @@ -111,7 +111,7 @@ int main() for (unsigned char c : szBuff) // Using hex() in HexCharStruct from checksum.cpp { - std::cout << "INT version:" << std::dec << (int)c << " " << std::endl; + //std::cout << "INT version:" << std::dec << (int)c << " " << std::endl; std::cout << "HEX version:" << hex(c) << " " << std::endl;; } std::cout << std::dec << std::endl; // Pretty sure this resets it back to decimal @@ -122,15 +122,5 @@ int main() std::cout << "Closing Handle..." << std::endl; CloseHandle(hSerial); std::cout << "Handle Closed." << std::endl; - - // It now reads the data fine, the only problem is leading zeros are - // removed, though they are implied/trivial to add back if I convert to - // string. - // Currently it reads 10 messeges of size 43 bytes then stops. - - // Next thing to do is work on sending a message in the correct - // format so that it understands, also recieving messages of - // different sizes. Also converting the data I get into readable/ - // usable data that means something to the rest of the program. } \ No newline at end of file From dc725ab6cd58885ad1e4e348791d28dcee7483b5 Mon Sep 17 00:00:00 2001 From: Matt Scalzo Date: Fri, 8 May 2020 02:11:31 -0400 Subject: [PATCH 11/12] Complete Actual Thing --- serialPortComs/serial.cpp | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/serialPortComs/serial.cpp b/serialPortComs/serial.cpp index 5e1bfd8..de51567 100644 --- a/serialPortComs/serial.cpp +++ b/serialPortComs/serial.cpp @@ -91,13 +91,11 @@ int main() std::cout << "Attempting to read data..." << std::endl; - int msgsToRead = 10; + int msgsToRead = 1000; int msgsRead = 0; while (msgsRead < msgsToRead) { - //std::cout << "Reading message number " << msgsRead + 1 << " out of " << msgsToRead << std::endl; - unsigned char szBuff[64 + 1] = {0}; // Buffer size DWORD dwBytesRead = 0; // Number of bytes actually read @@ -107,14 +105,33 @@ int main() return 9; } - //std::cout << "Bytes read: " << dwBytesRead << std::endl; + int index = -1; + + for (int i=0; i < 32; i++) // This gets the bytes for the Yaw angle + { + if (szBuff[i] == 0xFA && szBuff[i+1] == 0xFF && szBuff[i+2] == 0x36) + { + index = i + 22; + break; + } + } + + unsigned char yawArray[8]; - for (unsigned char c : szBuff) // Using hex() in HexCharStruct from checksum.cpp + if (index != -1) // This puts all those bytes { - //std::cout << "INT version:" << std::dec << (int)c << " " << std::endl; - std::cout << "HEX version:" << hex(c) << " " << std::endl;; + yawArray[0] = szBuff[index+8]; + yawArray[1] = szBuff[index+7]; + yawArray[2] = szBuff[index+6]; + yawArray[3] = szBuff[index+5]; + yawArray[4] = szBuff[index+4]; + yawArray[5] = szBuff[index+3]; + yawArray[6] = szBuff[index+2]; + yawArray[7] = szBuff[index+1]; } - std::cout << std::dec << std::endl; // Pretty sure this resets it back to decimal + double doubleYaw = *reinterpret_cast(yawArray); + + std::cout << "Yaw: " << doubleYaw << std::endl; msgsRead++; } @@ -122,7 +139,4 @@ int main() std::cout << "Closing Handle..." << std::endl; CloseHandle(hSerial); std::cout << "Handle Closed." << std::endl; - - // Once find a full message, just go to correct index and copy bytes I need. - } From d709efa10f5b778aca3f55ab1d937b1f08b05f32 Mon Sep 17 00:00:00 2001 From: Matt Scalzo Date: Fri, 8 May 2020 11:53:24 -0400 Subject: [PATCH 12/12] Create IO_Proc Files I think I did this correctly... we will see... --- .../include/AHRSOutputIOProcessor.hpp | 26 +++ .../io_procs/AHRSOutputIOProcessor.cpp | 150 ++++++++++++++++++ serialPortComs/serial.cpp | 26 +-- 3 files changed, 192 insertions(+), 10 deletions(-) create mode 100644 bfs/implementations/breadcrumbs/include/AHRSOutputIOProcessor.hpp create mode 100644 bfs/implementations/breadcrumbs/io_procs/AHRSOutputIOProcessor.cpp diff --git a/bfs/implementations/breadcrumbs/include/AHRSOutputIOProcessor.hpp b/bfs/implementations/breadcrumbs/include/AHRSOutputIOProcessor.hpp new file mode 100644 index 0000000..5e9eb3d --- /dev/null +++ b/bfs/implementations/breadcrumbs/include/AHRSOutputIOProcessor.hpp @@ -0,0 +1,26 @@ +#ifndef AHRS_OUTPUT_IO_PROCESSOR_HPP +#define AHRS_OUTPUT_IO_PROCESSOR_HPP + +#include "IOProcessor.hpp" +#include "DataSyncThread.hpp" +#include "Attribute.hpp" +#include +#include + +class AHRSOutputIOProcessor : public IOProcessor +{ +public: + using IOProcessor::IOProcessor; + + void loop(); + bool loopCondition(); + int configAHRS(); // Initialize the AHRS for the first time + +private: + int iterations = 10; + bool configured = false; + HANDLE hSerial; + +}; + +#endif \ No newline at end of file diff --git a/bfs/implementations/breadcrumbs/io_procs/AHRSOutputIOProcessor.cpp b/bfs/implementations/breadcrumbs/io_procs/AHRSOutputIOProcessor.cpp new file mode 100644 index 0000000..24c4026 --- /dev/null +++ b/bfs/implementations/breadcrumbs/io_procs/AHRSOutputIOProcessor.cpp @@ -0,0 +1,150 @@ +#include "AHRSOutputIOProcessor.hpp" + + +int AHRSOutputIOProcessor::configAHRS() +{ + DCB dcb = {0}; + //HANDLE hSerial; + + hSerial = CreateFile("COM8", // The COM port to connect to, may have to be changed + GENERIC_READ | GENERIC_WRITE, // depending on what COM port gets selected. + 0, + 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + 0); + + if (hSerial == INVALID_HANDLE_VALUE) + { + if(GetLastError() == ERROR_FILE_NOT_FOUND) + { + std::cout << "Serial port does not exist." << std::endl; + return 1; // serial port does not exist. + } + std::cout << "Some other error occurred." << std::endl; + return 2; // some other error occurred. + } + + dcb.DCBlength = sizeof(dcb); + + if (!GetCommState(hSerial, &dcb)) + { + std::cout << "Error getting state." << std::endl; + return 3; // error getting state. + } + + dcb.BaudRate = CBR_115200; // defualt baud rate of MT + dcb.ByteSize = 8; + dcb.StopBits = ONESTOPBIT; + dcb.Parity = NOPARITY; + + if (!SetCommState(hSerial, &dcb)) + { + std::cout << "Error setting serial port state." << std::endl; + return 4; // error setting serial port state + } + + COMMTIMEOUTS timeouts = {0}; + + timeouts.ReadIntervalTimeout = 50; + timeouts.ReadTotalTimeoutConstant = 50; + timeouts.ReadTotalTimeoutMultiplier = 10; + timeouts.WriteTotalTimeoutConstant = 50; + timeouts.WriteTotalTimeoutMultiplier = 10; + + if (!SetCommTimeouts(hSerial, &timeouts)) + { + std::cout << "Error occured while setting timoemouts." << std::endl; + return 5; + } + + std::cout << "Connection established!" << std::endl; + std::cout << "Setting up Config..." << std::endl; + + unsigned char wBuff1[] = {0xFA,0xFF,0x30,0x00,0xD1}; // This is the GoToConfig message + DWORD dwBytesWritten = 0; // Number of bytes actually written + + if (!WriteFile(hSerial, wBuff1, 6, &dwBytesWritten, NULL)) + { + std::cout << "Error occured while trying to send GoToConfig message." << std::endl; + return 6; + } + + unsigned char wBuff2[] = {0xFA,0xFF,0xC0,0x04,0x20,0x33,0x00,0x00,0xEA}; // This is the SetOutputConfiguration message + dwBytesWritten = 0; + + if (!WriteFile(hSerial, wBuff2, 10, &dwBytesWritten, NULL)) + { + std::cout << "Error occured while trying to send SetOutputConfiguration message." << std::endl; + return 7; + } + + unsigned char wBuff3[] = {0xFA,0xFF,0x10,0x00,0xF1}; // This is the GoToMeasurment message + dwBytesWritten = 0; + + if (!WriteFile(hSerial, wBuff3, 6, &dwBytesWritten, NULL)) + { + std::cout << "Error occured while trying to send GoToMeasurment message." << std::endl; + return 8; + } + + configured = true; + return 0; +} + +bool AHRSOutputIOProcessor::loopCondition() +{ + return iterations > 0; +} + +void AHRSOutputIOProcessor::loop() +{ + if (!configured) + configAHRS(); + + unsigned char szBuff[64 + 1] = {0}; // Buffer size + DWORD dwBytesRead = 0; // Number of bytes actually read + + if (!ReadFile(hSerial, szBuff, 64, &dwBytesRead, NULL)) + { + std::cout << "Error occured while trying to read bytes." << std::endl; + return 9; + } + + int index = -1; + + for (int i=0; i < 32; i++) // This gets the bytes for the Yaw angle + { + if (szBuff[i] == 0xFA && szBuff[i+1] == 0xFF && szBuff[i+2] == 0x36) + { + index = i + 22; + break; + } + } + + unsigned char yawArray[8]; + + if (index != -1) // This puts all those bytes + { + for (int i=0; i < 8; i++) + yawArray[i] = szBuff[index + (8-i)]; + // yawArray[0] = szBuff[index+8]; + // yawArray[1] = szBuff[index+7]; + // yawArray[2] = szBuff[index+6]; + // yawArray[3] = szBuff[index+5]; + // yawArray[4] = szBuff[index+4]; + // yawArray[5] = szBuff[index+3]; + // yawArray[6] = szBuff[index+2]; + // yawArray[7] = szBuff[index+1]; + } + double doubleYaw = *reinterpret_cast(yawArray); + + //std::cout << "Yaw: " << doubleYaw << std::endl; + + Attribute attrib("yawAngle", 8, &doubleYaw); + getComs()->sendAttribute(attriv); + iterations--; + + if (iterations == 0) + CloseHandle(hSerial); +} \ No newline at end of file diff --git a/serialPortComs/serial.cpp b/serialPortComs/serial.cpp index de51567..a10744c 100644 --- a/serialPortComs/serial.cpp +++ b/serialPortComs/serial.cpp @@ -4,11 +4,12 @@ int main() { + // This needs to be run once to configure the MT DCB dcb = {0}; HANDLE hSerial; - hSerial = CreateFile("COM8", // The COM port to connect to - GENERIC_READ | GENERIC_WRITE, + hSerial = CreateFile("COM8", // The COM port to connect to, may have to be changed + GENERIC_READ | GENERIC_WRITE, // depending on what COM port gets selected. 0, 0, OPEN_EXISTING, @@ -94,6 +95,7 @@ int main() int msgsToRead = 1000; int msgsRead = 0; + // This is the stuff that happens everytime while (msgsRead < msgsToRead) { unsigned char szBuff[64 + 1] = {0}; // Buffer size @@ -120,14 +122,18 @@ int main() if (index != -1) // This puts all those bytes { - yawArray[0] = szBuff[index+8]; - yawArray[1] = szBuff[index+7]; - yawArray[2] = szBuff[index+6]; - yawArray[3] = szBuff[index+5]; - yawArray[4] = szBuff[index+4]; - yawArray[5] = szBuff[index+3]; - yawArray[6] = szBuff[index+2]; - yawArray[7] = szBuff[index+1]; + for (int i=0; i < 8; i++) + { + yawArray[i] = szBuff[index + (8-i)]; + } + // yawArray[0] = szBuff[index+8]; + // yawArray[1] = szBuff[index+7]; + // yawArray[2] = szBuff[index+6]; + // yawArray[3] = szBuff[index+5]; + // yawArray[4] = szBuff[index+4]; + // yawArray[5] = szBuff[index+3]; + // yawArray[6] = szBuff[index+2]; + // yawArray[7] = szBuff[index+1]; } double doubleYaw = *reinterpret_cast(yawArray);