Included are 2 wireshark logs. These logs include usb communication to a custom device that has buttons and USB screens. The working dissection log is a piece of data from a black box - it's an example of connecting to the device, settings the brightness of the screens, displaying images on the screens, and then disconnecting the device. The failing dissection log is from the code I'm working on. Finally, the code itself used to produce the failing log has been shared. In the failing version, the screens never light up, and the device doesn't seem to be de-initialized properly when done. In the working log, there may be other behaviors going on unseen, but as it's a black box I'm unsure of what they might be.

Try and break down what's happening here in a human understandable way. What messages might I specifically need to add to my code? Can you help decipher the message protocol a bit better, especially in relation to the code shared?

// WORKING WIRESHARK DISSECTION CSV BELOW HERE //

"No.","Time","Source","Destination","Protocol","Length","Info"
"1","0.000000","host","3.1.0","USB","36","GET DESCRIPTOR Request DEVICE"
"2","0.000000","3.1.0","host","USB","46","GET DESCRIPTOR Response DEVICE"
"3","0.000000","host","3.1.0","USB","36","GET DESCRIPTOR Request CONFIGURATION"
"4","0.000000","3.1.0","host","USB","319","GET DESCRIPTOR Response CONFIGURATION"
"5","0.000000","host","3.1.0","USB","36","SET CONFIGURATION Request"
"6","0.000000","3.1.0","host","USB","28","SET CONFIGURATION Response"
"7","7.827838","host","3.1.1","USB","27","URB_BULK in"
"8","7.827866","host","3.1.2","USB","27","URB_INTERRUPT in"
"9","7.827892","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"10","7.828076","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"11","7.828097","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"12","7.828449","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"13","7.828540","3.1.1","host","USB","27","URB_BULK in"
"14","7.828617","3.1.2","host","USB","27","URB_INTERRUPT in"
"15","7.828642","host","3.1.0","USBCOM","36","SET CONTROL LINE STATE Request"
"16","7.828701","3.1.0","host","USB","28","URB_CONTROL out"
"17","7.844910","host","3.1.1","USB","27","URB_BULK in"
"18","7.844931","host","3.1.2","USB","27","URB_INTERRUPT in"
"19","7.844969","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"20","7.845202","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"21","7.845219","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"22","7.845574","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"23","7.845614","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"24","7.845951","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"25","7.845967","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"26","7.846319","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"27","7.846340","host","3.1.0","USBCOM","43","SET LINE CODING Request"
"28","7.846953","3.1.0","host","USB","28","URB_CONTROL out"
"29","7.846966","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"30","7.847321","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"31","7.847341","host","3.1.0","USBCOM","36","SET CONTROL LINE STATE Request"
"32","7.847575","3.1.0","host","USB","28","URB_CONTROL out"
"33","7.847592","host","3.1.0","USBCOM","43","SET LINE CODING Request"
"34","7.848203","3.1.0","host","USB","28","URB_CONTROL out"
"35","7.848214","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"36","7.848572","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"37","7.848593","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"38","7.848949","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"39","7.848965","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"40","7.849322","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"41","7.849350","host","3.1.0","USBCOM","43","SET LINE CODING Request"
"42","7.849950","3.1.0","host","USB","28","URB_CONTROL out"
"43","7.849959","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"44","7.850321","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"45","7.850335","host","3.1.0","USBCOM","36","SET CONTROL LINE STATE Request"
"46","7.850571","3.1.0","host","USB","28","URB_CONTROL out"
"47","7.850582","host","3.1.0","USBCOM","43","SET LINE CODING Request"
"48","7.851199","3.1.0","host","USB","28","URB_CONTROL out"
"49","7.851208","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"50","7.851571","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"51","7.851592","host","3.1.0","USBCOM","36","SET CONTROL LINE STATE Request"
"52","7.851824","3.1.0","host","USB","28","URB_CONTROL out"
"53","7.852354","host","3.1.0","USBCOM","36","SEND BREAK Request"
"54","7.852449","3.1.0","host","USB","28","URB_CONTROL out"
"55","7.873691","host","3.1.0","USBCOM","36","SEND BREAK Request"
"56","7.873826","3.1.0","host","USB","28","URB_CONTROL out"
"57","7.982270","host","3.1.0","USBCOM","36","SEND BREAK Request"
"58","7.982456","3.1.0","host","USB","28","URB_CONTROL out"
"59","8.091278","host","3.1.0","USBCOM","36","SEND BREAK Request"
"60","8.091457","3.1.0","host","USB","28","URB_CONTROL out"
"61","8.094230","host","3.1.1","USBCOM","141","URB_BULK out"
"62","8.094299","3.1.1","host","USB","27","URB_BULK out"
"63","8.094495","3.1.1","host","USBCOM","156","URB_BULK in"
"64","8.094525","host","3.1.1","USB","27","URB_BULK in"
"65","8.094560","3.1.1","host","USBCOM","29","URB_BULK in"
"66","8.094564","host","3.1.1","USB","27","URB_BULK in"
"67","8.094600","3.1.1","host","USBCOM","56","URB_BULK in"
"68","8.094607","host","3.1.1","USB","27","URB_BULK in"
"69","8.094644","3.1.1","host","USBCOM","29","URB_BULK in"
"70","8.094648","host","3.1.1","USB","27","URB_BULK in"
"71","8.094688","3.1.1","host","USBCOM","51","URB_BULK in"
"72","8.094697","host","3.1.1","USB","27","URB_BULK in"
"73","8.094734","3.1.1","host","USBCOM","29","URB_BULK in"
"74","8.094743","host","3.1.1","USB","27","URB_BULK in"
"75","8.094772","3.1.1","host","USBCOM","50","URB_BULK in"
"76","8.094779","host","3.1.1","USB","27","URB_BULK in"
"77","8.094813","3.1.1","host","USBCOM","29","URB_BULK in"
"78","8.094821","host","3.1.1","USB","27","URB_BULK in"
"79","8.094853","3.1.1","host","USBCOM","75","URB_BULK in"
"80","8.094861","host","3.1.1","USB","27","URB_BULK in"
"81","8.094894","3.1.1","host","USBCOM","29","URB_BULK in"
"82","8.094901","host","3.1.1","USB","27","URB_BULK in"
"83","8.094939","3.1.1","host","USBCOM","32","URB_BULK in"
"84","8.094944","host","3.1.1","USB","27","URB_BULK in"
"85","8.094979","3.1.1","host","USBCOM","29","URB_BULK in"
"86","8.094987","host","3.1.1","USB","27","URB_BULK in"
"87","8.095022","3.1.1","host","USBCOM","58","URB_BULK in"
"88","8.095029","host","3.1.1","USB","27","URB_BULK in"
"89","8.095064","3.1.1","host","USBCOM","29","URB_BULK in"
"90","8.095070","host","3.1.1","USB","27","URB_BULK in"
"91","8.095102","3.1.1","host","USBCOM","55","URB_BULK in"
"92","8.095107","host","3.1.1","USB","27","URB_BULK in"
"93","8.104238","host","3.1.1","USBCOM","33","URB_BULK out"
"94","8.104284","3.1.1","host","USB","27","URB_BULK out"
"95","8.104323","host","3.1.1","USBCOM","46","URB_BULK out"
"96","8.104339","3.1.1","host","USB","27","URB_BULK out"
"97","8.104381","3.1.1","host","USBCOM","29","URB_BULK in"
"98","8.104391","host","3.1.1","USB","27","URB_BULK in"
"99","8.104423","3.1.1","host","USBCOM","46","URB_BULK in"
"100","8.104428","host","3.1.1","USB","27","URB_BULK in"
"101","8.107755","host","3.1.1","USBCOM","33","URB_BULK out"
"102","8.107811","3.1.1","host","USB","27","URB_BULK out"
"103","8.107840","host","3.1.1","USBCOM","46","URB_BULK out"
"104","8.107855","3.1.1","host","USB","27","URB_BULK out"
"105","8.107905","3.1.1","host","USBCOM","29","URB_BULK in"
"106","8.107914","host","3.1.1","USB","27","URB_BULK in"
"107","8.107948","3.1.1","host","USBCOM","46","URB_BULK in"
"108","8.107956","host","3.1.1","USB","27","URB_BULK in"
"109","8.115181","host","3.1.1","USBCOM","33","URB_BULK out"
"110","8.115224","3.1.1","host","USB","27","URB_BULK out"
"111","8.115278","host","3.1.1","USBCOM","30","URB_BULK out"
"112","8.115300","3.1.1","host","USB","27","URB_BULK out"
"113","8.115330","3.1.1","host","USBCOM","29","URB_BULK in"
"114","8.115340","host","3.1.1","USB","27","URB_BULK in"
"115","8.115379","3.1.1","host","USBCOM","39","URB_BULK in"
"116","8.115384","host","3.1.1","USB","27","URB_BULK in"
"117","8.116179","host","3.1.1","USBCOM","33","URB_BULK out"
"118","8.116214","3.1.1","host","USB","27","URB_BULK out"
"119","8.116246","host","3.1.1","USBCOM","30","URB_BULK out"
"120","8.116259","3.1.1","host","USB","27","URB_BULK out"
"121","8.116292","3.1.1","host","USBCOM","29","URB_BULK in"
"122","8.116298","host","3.1.1","USB","27","URB_BULK in"
"123","8.116341","3.1.1","host","USBCOM","51","URB_BULK in"
"124","8.116347","host","3.1.1","USB","27","URB_BULK in"
"125","8.143966","host","3.1.1","USBCOM","33","URB_BULK out"
"126","8.144013","3.1.1","host","USB","27","URB_BULK out"
"127","8.144071","host","3.1.1","USBCOM","30","URB_BULK out"
"128","8.144103","3.1.1","host","USB","27","URB_BULK out"
"129","8.144125","3.1.1","host","USBCOM","29","URB_BULK in"
"130","8.144141","host","3.1.1","USB","27","URB_BULK in"
"131","8.144171","3.1.1","host","USBCOM","34","URB_BULK in"
"132","8.144175","host","3.1.1","USB","27","URB_BULK in"
"133","8.144670","host","3.1.1","USBCOM","33","URB_BULK out"
"134","8.144701","3.1.1","host","USB","27","URB_BULK out"
"135","8.144748","host","3.1.1","USBCOM","30","URB_BULK out"
"136","8.144767","3.1.1","host","USB","27","URB_BULK out"
"137","8.144801","3.1.1","host","USBCOM","29","URB_BULK in"
"138","8.144808","host","3.1.1","USB","27","URB_BULK in"
"139","8.144840","3.1.1","host","USBCOM","58","URB_BULK in"
"140","8.144846","host","3.1.1","USB","27","URB_BULK in"
"141","8.145832","host","3.1.1","USBCOM","33","URB_BULK out"
"142","8.145860","3.1.1","host","USB","27","URB_BULK out"
"143","8.145895","host","3.1.1","USBCOM","31","URB_BULK out"
"144","8.145917","3.1.1","host","USB","27","URB_BULK out"
"145","8.145954","3.1.1","host","USBCOM","29","URB_BULK in"
"146","8.145961","host","3.1.1","USB","27","URB_BULK in"
"147","8.146003","3.1.1","host","USBCOM","35","URB_BULK in"
"148","8.146008","host","3.1.1","USB","27","URB_BULK in"
"149","8.146632","host","3.1.1","USBCOM","33","URB_BULK out"
"150","8.146680","3.1.1","host","USB","27","URB_BULK out"
"151","8.146706","host","3.1.1","USBCOM","31","URB_BULK out"
"152","8.146730","3.1.1","host","USB","27","URB_BULK out"
"153","8.146754","3.1.1","host","USBCOM","29","URB_BULK in"
"154","8.146759","host","3.1.1","USB","27","URB_BULK in"
"155","8.146800","3.1.1","host","USBCOM","35","URB_BULK in"
"156","8.146805","host","3.1.1","USB","27","URB_BULK in"
"157","8.146950","host","3.1.1","USBCOM","33","URB_BULK out"
"158","8.146968","3.1.1","host","USB","27","URB_BULK out"
"159","8.147001","host","3.1.1","USBCOM","31","URB_BULK out"
"160","8.147019","3.1.1","host","USB","27","URB_BULK out"
"161","8.147058","3.1.1","host","USBCOM","29","URB_BULK in"
"162","8.147065","host","3.1.1","USB","27","URB_BULK in"
"163","8.147101","3.1.1","host","USBCOM","35","URB_BULK in"
"164","8.147107","host","3.1.1","USB","27","URB_BULK in"
"165","8.147241","host","3.1.1","USBCOM","33","URB_BULK out"
"166","8.147263","3.1.1","host","USB","27","URB_BULK out"
"167","8.147292","host","3.1.1","USBCOM","31","URB_BULK out"
"168","8.147311","3.1.1","host","USB","27","URB_BULK out"
"169","8.147344","3.1.1","host","USBCOM","29","URB_BULK in"
"170","8.147350","host","3.1.1","USB","27","URB_BULK in"
"171","8.147390","3.1.1","host","USBCOM","35","URB_BULK in"
"172","8.147397","host","3.1.1","USB","27","URB_BULK in"
"173","8.147898","host","3.1.1","USBCOM","33","URB_BULK out"
"174","8.147929","3.1.1","host","USB","27","URB_BULK out"
"175","8.147963","host","3.1.1","USBCOM","30","URB_BULK out"
"176","8.147982","3.1.1","host","USB","27","URB_BULK out"
"177","8.148035","3.1.1","host","USBCOM","31","URB_BULK in"
"178","8.148044","host","3.1.1","USB","27","URB_BULK in"
"179","8.148082","3.1.1","host","USBCOM","281","URB_BULK in"
"180","8.148089","host","3.1.1","USB","27","URB_BULK in"
"181","8.148127","3.1.1","host","USBCOM","31","URB_BULK in"
"182","8.148135","host","3.1.1","USB","27","URB_BULK in"
"183","8.148169","3.1.1","host","USBCOM","281","URB_BULK in"
"184","8.148178","host","3.1.1","USB","27","URB_BULK in"
"185","8.148206","3.1.1","host","USBCOM","31","URB_BULK in"
"186","8.148214","host","3.1.1","USB","27","URB_BULK in"
"187","8.148254","3.1.1","host","USBCOM","281","URB_BULK in"
"188","8.148261","host","3.1.1","USB","27","URB_BULK in"
"189","8.148294","3.1.1","host","USBCOM","31","URB_BULK in"
"190","8.148301","host","3.1.1","USB","27","URB_BULK in"
"191","8.148331","3.1.1","host","USBCOM","281","URB_BULK in"
"192","8.148337","host","3.1.1","USB","27","URB_BULK in"
"193","8.151686","host","3.1.1","USBCOM","33","URB_BULK out"
"194","8.151724","3.1.1","host","USB","27","URB_BULK out"
"195","8.151757","host","3.1.1","USBCOM","30","URB_BULK out"
"196","8.151771","3.1.1","host","USB","27","URB_BULK out"
"197","8.162377","3.1.1","host","USBCOM","29","URB_BULK in"
"198","8.162391","host","3.1.1","USB","27","URB_BULK in"
"199","8.162418","3.1.1","host","USBCOM","31","URB_BULK in"
"200","8.162424","host","3.1.1","USB","27","URB_BULK in"
"201","8.162554","host","3.1.1","USBCOM","33","URB_BULK out"
"202","8.162584","3.1.1","host","USB","27","URB_BULK out"
"203","8.162620","host","3.1.1","USBCOM","31","URB_BULK out"
"204","8.162640","3.1.1","host","USB","27","URB_BULK out"
"205","8.162679","3.1.1","host","USBCOM","29","URB_BULK in"
"206","8.162686","host","3.1.1","USB","27","URB_BULK in"
"207","8.162719","3.1.1","host","USBCOM","31","URB_BULK in"
"208","8.162724","host","3.1.1","USB","27","URB_BULK in"
"209","8.278383","host","3.1.1","USBCOM","33","URB_BULK out"
"210","8.278441","3.1.1","host","USB","27","URB_BULK out"
"211","8.278494","host","3.1.1","USBCOM","31","URB_BULK out"
"212","8.278521","3.1.1","host","USB","27","URB_BULK out"
"213","8.278553","3.1.1","host","USBCOM","29","URB_BULK in"
"214","8.278564","host","3.1.1","USB","27","URB_BULK in"
"215","8.278596","3.1.1","host","USBCOM","31","URB_BULK in"
"216","8.278602","host","3.1.1","USB","27","URB_BULK in"
"217","16.941001","host","3.1.1","USBCOM","41","URB_BULK out"
"218","16.941059","3.1.1","host","USB","27","URB_BULK out"
"219","16.941102","host","3.1.1","USBCOM","40","URB_BULK out"
"220","16.941123","3.1.1","host","USB","27","URB_BULK out"
"221","16.941231","host","3.1.1","USBCOM","388827","URB_BULK out"
"222","16.965079","3.1.1","host","USB","27","URB_BULK out"
"223","16.965383","host","3.1.1","USBCOM","33","URB_BULK out"
"224","16.965449","3.1.1","host","USB","27","URB_BULK out"
"225","16.965508","host","3.1.1","USBCOM","32","URB_BULK out"
"226","16.965676","3.1.1","host","USB","27","URB_BULK out"
"227","16.965709","3.1.1","host","USBCOM","29","URB_BULK in"
"228","16.965721","host","3.1.1","USB","27","URB_BULK in"
"229","16.965751","3.1.1","host","USBCOM","31","URB_BULK in"
"230","16.965756","host","3.1.1","USB","27","URB_BULK in"
"231","16.965788","3.1.1","host","USBCOM","29","URB_BULK in"
"232","16.965793","host","3.1.1","USB","27","URB_BULK in"
"233","16.965836","3.1.1","host","USBCOM","31","URB_BULK in"
"234","16.965844","host","3.1.1","USB","27","URB_BULK in"
"235","17.119740","host","3.1.1","USBCOM","35","URB_BULK out"
"236","17.119897","3.1.1","host","USB","27","URB_BULK out"
"237","17.119970","host","3.1.1","USBCOM","40","URB_BULK out"
"238","17.120005","3.1.1","host","USB","27","URB_BULK out"
"239","17.120058","host","3.1.1","USBCOM","15579","URB_BULK out"
"240","17.121011","3.1.1","host","USB","27","URB_BULK out"
"241","17.121069","host","3.1.1","USBCOM","33","URB_BULK out"
"242","17.121109","3.1.1","host","USBCOM","29","URB_BULK in"
"243","17.121129","3.1.1","host","USB","27","URB_BULK out"
"244","17.121136","host","3.1.1","USB","27","URB_BULK in"
"245","17.121151","3.1.1","host","USBCOM","31","URB_BULK in"
"246","17.121155","host","3.1.1","USB","27","URB_BULK in"
"247","17.121169","host","3.1.1","USBCOM","32","URB_BULK out"
"248","17.121194","3.1.1","host","USB","27","URB_BULK out"
"249","17.121227","3.1.1","host","USBCOM","29","URB_BULK in"
"250","17.121234","host","3.1.1","USB","27","URB_BULK in"
"251","17.121271","3.1.1","host","USBCOM","31","URB_BULK in"
"252","17.121280","host","3.1.1","USB","27","URB_BULK in"
"253","18.131971","host","3.1.1","USBCOM","35","URB_BULK out"
"254","18.132039","3.1.1","host","USB","27","URB_BULK out"
"255","18.132093","host","3.1.1","USBCOM","40","URB_BULK out"
"256","18.132127","3.1.1","host","USB","27","URB_BULK out"
"257","18.132176","host","3.1.1","USBCOM","15579","URB_BULK out"
"258","18.133087","3.1.1","host","USB","27","URB_BULK out"
"259","18.133155","host","3.1.1","USBCOM","33","URB_BULK out"
"260","18.133183","3.1.1","host","USBCOM","29","URB_BULK in"
"261","18.133201","3.1.1","host","USB","27","URB_BULK out"
"262","18.133209","host","3.1.1","USB","27","URB_BULK in"
"263","18.133229","3.1.1","host","USBCOM","31","URB_BULK in"
"264","18.133234","host","3.1.1","USB","27","URB_BULK in"
"265","18.133244","host","3.1.1","USBCOM","32","URB_BULK out"
"266","18.133265","3.1.1","host","USB","27","URB_BULK out"
"267","18.133300","3.1.1","host","USBCOM","29","URB_BULK in"
"268","18.133308","host","3.1.1","USB","27","URB_BULK in"
"269","18.133342","3.1.1","host","USBCOM","31","URB_BULK in"
"270","18.133350","host","3.1.1","USB","27","URB_BULK in"
"271","18.249030","host","3.1.1","USBCOM","41","URB_BULK out"
"272","18.249084","3.1.1","host","USB","27","URB_BULK out"
"273","18.249125","host","3.1.1","USBCOM","40","URB_BULK out"
"274","18.249140","3.1.1","host","USB","27","URB_BULK out"
"275","18.249230","host","3.1.1","USBCOM","388827","URB_BULK out"
"276","18.271391","3.1.1","host","USB","27","URB_BULK out"
"277","18.271470","host","3.1.1","USBCOM","33","URB_BULK out"
"278","18.271487","3.1.1","host","USB","27","URB_BULK out"
"279","18.271550","host","3.1.1","USBCOM","32","URB_BULK out"
"280","18.271998","3.1.1","host","USB","27","URB_BULK out"
"281","18.272025","3.1.1","host","USBCOM","29","URB_BULK in"
"282","18.272039","host","3.1.1","USB","27","URB_BULK in"
"283","18.272063","3.1.1","host","USBCOM","31","URB_BULK in"
"284","18.272082","host","3.1.1","USB","27","URB_BULK in"
"285","18.272106","3.1.1","host","USBCOM","29","URB_BULK in"
"286","18.272113","host","3.1.1","USB","27","URB_BULK in"
"287","18.272233","3.1.1","host","USBCOM","31","URB_BULK in"
"288","18.272241","host","3.1.1","USB","27","URB_BULK in"
"289","19.144587","host","3.1.1","USBCOM","35","URB_BULK out"
"290","19.144645","3.1.1","host","USB","27","URB_BULK out"
"291","19.144680","host","3.1.1","USBCOM","40","URB_BULK out"
"292","19.144697","3.1.1","host","USB","27","URB_BULK out"
"293","19.144717","host","3.1.1","USBCOM","15579","URB_BULK out"
"294","19.145675","3.1.1","host","USB","27","URB_BULK out"
"295","19.145715","host","3.1.1","USBCOM","33","URB_BULK out"
"296","19.145732","3.1.1","host","USB","27","URB_BULK out"
"297","19.145750","host","3.1.1","USBCOM","32","URB_BULK out"
"298","19.145773","3.1.1","host","USB","27","URB_BULK out"
"299","19.145778","3.1.1","host","USBCOM","29","URB_BULK in"
"300","19.145789","host","3.1.1","USB","27","URB_BULK in"
"301","19.145823","3.1.1","host","USBCOM","31","URB_BULK in"
"302","19.145828","host","3.1.1","USB","27","URB_BULK in"
"303","19.145867","3.1.1","host","USBCOM","29","URB_BULK in"
"304","19.145871","host","3.1.1","USB","27","URB_BULK in"
"305","19.145908","3.1.1","host","USBCOM","31","URB_BULK in"
"306","19.145914","host","3.1.1","USB","27","URB_BULK in"
"307","19.258295","host","3.1.1","USBCOM","41","URB_BULK out"
"308","19.258358","3.1.1","host","USB","27","URB_BULK out"
"309","19.258406","host","3.1.1","USBCOM","40","URB_BULK out"
"310","19.258428","3.1.1","host","USB","27","URB_BULK out"
"311","19.258486","host","3.1.1","USBCOM","388827","URB_BULK out"
"312","19.282109","3.1.1","host","USB","27","URB_BULK out"
"313","19.282177","host","3.1.1","USBCOM","33","URB_BULK out"
"314","19.282206","3.1.1","host","USB","27","URB_BULK out"
"315","19.282228","host","3.1.1","USBCOM","32","URB_BULK out"
"316","19.282722","3.1.1","host","USB","27","URB_BULK out"
"317","19.282771","3.1.1","host","USBCOM","29","URB_BULK in"
"318","19.282785","host","3.1.1","USB","27","URB_BULK in"
"319","19.282813","3.1.1","host","USBCOM","31","URB_BULK in"
"320","19.282817","host","3.1.1","USB","27","URB_BULK in"
"321","19.282851","3.1.1","host","USBCOM","29","URB_BULK in"
"322","19.282856","host","3.1.1","USB","27","URB_BULK in"
"323","19.282900","3.1.1","host","USBCOM","31","URB_BULK in"
"324","19.282904","host","3.1.1","USB","27","URB_BULK in"
"325","20.153812","host","3.1.1","USBCOM","35","URB_BULK out"
"326","20.154057","3.1.1","host","USB","27","URB_BULK out"
"327","20.154099","host","3.1.1","USBCOM","40","URB_BULK out"
"328","20.154122","3.1.1","host","USB","27","URB_BULK out"
"329","20.154144","host","3.1.1","USBCOM","15579","URB_BULK out"
"330","20.155067","3.1.1","host","USB","27","URB_BULK out"
"331","20.155097","host","3.1.1","USBCOM","33","URB_BULK out"
"332","20.155118","3.1.1","host","USB","27","URB_BULK out"
"333","20.155131","host","3.1.1","USBCOM","32","URB_BULK out"
"334","20.155161","3.1.1","host","USB","27","URB_BULK out"
"335","20.155183","3.1.1","host","USBCOM","29","URB_BULK in"
"336","20.155194","host","3.1.1","USB","27","URB_BULK in"
"337","20.155225","3.1.1","host","USBCOM","31","URB_BULK in"
"338","20.155231","host","3.1.1","USB","27","URB_BULK in"
"339","20.155262","3.1.1","host","USBCOM","29","URB_BULK in"
"340","20.155266","host","3.1.1","USB","27","URB_BULK in"
"341","20.155305","3.1.1","host","USBCOM","31","URB_BULK in"
"342","20.155310","host","3.1.1","USB","27","URB_BULK in"
"343","21.165669","host","3.1.1","USBCOM","35","URB_BULK out"
"344","21.165732","3.1.1","host","USB","27","URB_BULK out"
"345","21.165769","host","3.1.1","USBCOM","40","URB_BULK out"
"346","21.165786","3.1.1","host","USB","27","URB_BULK out"
"347","21.165821","host","3.1.1","USBCOM","15579","URB_BULK out"
"348","21.166773","3.1.1","host","USB","27","URB_BULK out"
"349","21.166819","host","3.1.1","USBCOM","33","URB_BULK out"
"350","21.166844","3.1.1","host","USB","27","URB_BULK out"
"351","21.166860","host","3.1.1","USBCOM","32","URB_BULK out"
"352","21.166878","3.1.1","host","USBCOM","29","URB_BULK in"
"353","21.166879","3.1.1","host","USB","27","URB_BULK out"
"354","21.166891","host","3.1.1","USB","27","URB_BULK in"
"355","21.166923","3.1.1","host","USBCOM","31","URB_BULK in"
"356","21.166929","host","3.1.1","USB","27","URB_BULK in"
"357","21.166963","3.1.1","host","USBCOM","29","URB_BULK in"
"358","21.166968","host","3.1.1","USB","27","URB_BULK in"
"359","21.167011","3.1.1","host","USBCOM","31","URB_BULK in"
"360","21.167017","host","3.1.1","USB","27","URB_BULK in"
"361","22.177455","host","3.1.1","USBCOM","35","URB_BULK out"
"362","22.177518","3.1.1","host","USB","27","URB_BULK out"
"363","22.177557","host","3.1.1","USBCOM","40","URB_BULK out"
"364","22.177577","3.1.1","host","USB","27","URB_BULK out"
"365","22.177598","host","3.1.1","USBCOM","15579","URB_BULK out"
"366","22.178528","3.1.1","host","USB","27","URB_BULK out"
"367","22.178582","host","3.1.1","USBCOM","33","URB_BULK out"
"368","22.178613","3.1.1","host","USB","27","URB_BULK out"
"369","22.178629","host","3.1.1","USBCOM","32","URB_BULK out"
"370","22.178636","3.1.1","host","USBCOM","29","URB_BULK in"
"371","22.178649","host","3.1.1","USB","27","URB_BULK in"
"372","22.178663","3.1.1","host","USB","27","URB_BULK out"
"373","22.178684","3.1.1","host","USBCOM","31","URB_BULK in"
"374","22.178690","host","3.1.1","USB","27","URB_BULK in"
"375","22.178719","3.1.1","host","USBCOM","29","URB_BULK in"
"376","22.178724","host","3.1.1","USB","27","URB_BULK in"
"377","22.178758","3.1.1","host","USBCOM","31","URB_BULK in"
"378","22.178764","host","3.1.1","USB","27","URB_BULK in"
"379","22.843739","host","3.1.1","USBCOM","33","URB_BULK out"
"380","22.843815","3.1.1","host","USB","27","URB_BULK out"
"381","22.843861","host","3.1.1","USBCOM","30","URB_BULK out"
"382","22.843883","3.1.1","host","USB","27","URB_BULK out"
"383","22.854493","3.1.1","host","USBCOM","29","URB_BULK in"
"384","22.854528","host","3.1.1","USB","27","URB_BULK in"
"385","22.854550","3.1.1","host","USBCOM","31","URB_BULK in"
"386","22.854556","host","3.1.1","USB","27","URB_BULK in"
"387","22.854710","host","3.1.1","USBCOM","33","URB_BULK out"
"388","22.854742","3.1.1","host","USB","27","URB_BULK out"
"389","22.854772","host","3.1.1","USBCOM","31","URB_BULK out"
"390","22.854788","3.1.1","host","USB","27","URB_BULK out"
"391","22.854827","3.1.1","host","USBCOM","29","URB_BULK in"
"392","22.854835","host","3.1.1","USB","27","URB_BULK in"
"393","22.854875","3.1.1","host","USBCOM","31","URB_BULK in"
"394","22.854881","host","3.1.1","USB","27","URB_BULK in"
"395","22.969347","host","3.1.0","USBCOM","36","SEND BREAK Request"
"396","22.969463","3.1.0","host","USB","28","URB_CONTROL out"
"397","22.983221","host","3.1.0","USBCOM","36","SEND BREAK Request"
"398","22.983349","3.1.0","host","USB","28","URB_CONTROL out"
"399","23.094059","host","3.1.0","USBCOM","36","SEND BREAK Request"
"400","23.094213","3.1.0","host","USB","28","URB_CONTROL out"
"401","23.204050","host","3.1.0","USBCOM","36","SEND BREAK Request"
"402","23.204215","3.1.0","host","USB","28","URB_CONTROL out"
"403","23.204506","host","3.1.0","USBCOM","36","SET CONTROL LINE STATE Request"
"404","23.204583","3.1.0","host","USB","28","URB_CONTROL out"
"405","23.204690","3.1.1","host","USB","27","URB_BULK in"
"406","23.204783","3.1.2","host","USB","27","URB_INTERRUPT in"
"407","23.204809","host","3.1.0","USBCOM","36","SET CONTROL LINE STATE Request"
"408","23.204831","3.1.0","host","USB","28","URB_CONTROL out"


// FAILING WIRESHARK DISSECTION CSV BELOW HERE //

"No.","Time","Source","Destination","Protocol","Length","Info"
"1","0.000000","host","3.1.0","USB","36","GET DESCRIPTOR Request DEVICE"
"2","0.000000","3.1.0","host","USB","46","GET DESCRIPTOR Response DEVICE"
"3","0.000000","host","3.1.0","USB","36","GET DESCRIPTOR Request CONFIGURATION"
"4","0.000000","3.1.0","host","USB","319","GET DESCRIPTOR Response CONFIGURATION"
"5","0.000000","host","3.1.0","USB","36","SET CONFIGURATION Request"
"6","0.000000","3.1.0","host","USB","28","SET CONFIGURATION Response"
"7","1.430188","host","3.1.1","USB","27","URB_BULK in"
"8","1.430216","host","3.1.2","USB","27","URB_INTERRUPT in"
"9","1.430233","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"10","1.430471","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"11","1.430491","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"12","1.430844","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"13","1.430870","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"14","1.431217","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"15","1.431229","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"16","1.431597","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"17","1.431612","host","3.1.0","USBCOM","43","SET LINE CODING Request"
"18","1.432228","3.1.0","host","USB","28","URB_CONTROL out"
"19","1.432237","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"20","1.432602","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"21","1.432618","host","3.1.0","USBCOM","36","SET CONTROL LINE STATE Request"
"22","1.432843","3.1.0","host","USB","28","URB_CONTROL out"
"23","1.432854","host","3.1.0","USBCOM","43","SET LINE CODING Request"
"24","1.433472","3.1.0","host","USB","28","URB_CONTROL out"
"25","1.433491","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"26","1.433843","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"27","1.433864","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"28","1.434223","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"29","1.434234","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"30","1.434597","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"31","1.434613","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"32","1.434972","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"33","1.434988","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"34","1.435349","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"35","1.435365","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"36","1.435719","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"37","1.435735","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"38","1.436093","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"39","1.436118","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"40","1.436474","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"41","1.436490","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"42","1.436844","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"43","1.436864","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"44","1.437221","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"45","1.437233","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"46","1.437598","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"47","1.437694","3.1.1","host","USB","27","URB_BULK in"
"48","1.437775","3.1.2","host","USB","27","URB_INTERRUPT in"
"49","1.437790","host","3.1.0","USBCOM","36","SET CONTROL LINE STATE Request"
"50","1.437843","3.1.0","host","USB","28","URB_CONTROL out"
"51","1.437865","host","3.1.1","USB","27","URB_BULK in"
"52","1.437870","host","3.1.2","USB","27","URB_INTERRUPT in"
"53","1.437882","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"54","1.438223","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"55","1.438234","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"56","1.438598","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"57","1.438615","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"58","1.438973","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"59","1.439017","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"60","1.439345","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"61","1.439373","host","3.1.0","USBCOM","43","SET LINE CODING Request"
"62","1.439974","3.1.0","host","USB","28","URB_CONTROL out"
"63","1.439987","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"64","1.440348","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"65","1.440365","host","3.1.0","USBCOM","36","SET CONTROL LINE STATE Request"
"66","1.440597","3.1.0","host","USB","28","URB_CONTROL out"
"67","1.440611","host","3.1.0","USBCOM","43","SET LINE CODING Request"
"68","1.441221","3.1.0","host","USB","28","URB_CONTROL out"
"69","1.441230","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"70","1.441597","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"71","1.441615","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"72","1.441972","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"73","1.441984","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"74","1.442347","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"75","1.442367","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"76","1.442722","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"77","1.442733","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"78","1.443094","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"79","1.443110","host","3.1.0","USBCOM","43","SET LINE CODING Request"
"80","1.443723","3.1.0","host","USB","28","URB_CONTROL out"
"81","1.443732","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"82","1.444093","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"83","1.444107","host","3.1.0","USBCOM","36","SET CONTROL LINE STATE Request"
"84","1.444347","3.1.0","host","USB","28","URB_CONTROL out"
"85","1.444358","host","3.1.0","USBCOM","43","SET LINE CODING Request"
"86","1.444972","3.1.0","host","USB","28","URB_CONTROL out"
"87","1.444981","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"88","1.445348","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"89","1.445363","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"90","1.445723","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"91","1.445733","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"92","1.446093","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"93","1.446108","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"94","1.446472","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"95","1.446483","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"96","1.446843","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"97","1.446858","host","3.1.0","USBCOM","43","SET LINE CODING Request"
"98","1.447473","3.1.0","host","USB","28","URB_CONTROL out"
"99","1.447482","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"100","1.447843","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"101","1.447860","host","3.1.0","USBCOM","36","SET CONTROL LINE STATE Request"
"102","1.448094","3.1.0","host","USB","28","URB_CONTROL out"
"103","1.448104","host","3.1.0","USBCOM","43","SET LINE CODING Request"
"104","1.448729","3.1.0","host","USB","28","URB_CONTROL out"
"105","1.448736","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"106","1.449098","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"107","1.449112","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"108","1.449473","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"109","1.449484","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"110","1.449844","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"111","1.449858","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"112","1.450222","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"113","1.450233","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"114","1.450597","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"115","1.450615","host","3.1.0","USBCOM","43","SET LINE CODING Request"
"116","1.451221","3.1.0","host","USB","28","URB_CONTROL out"
"117","1.451229","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"118","1.451598","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"119","1.451612","host","3.1.0","USBCOM","36","SET CONTROL LINE STATE Request"
"120","1.451843","3.1.0","host","USB","28","URB_CONTROL out"
"121","1.451893","host","3.1.0","USBCOM","43","SET LINE CODING Request"
"122","1.452473","3.1.0","host","USB","28","URB_CONTROL out"
"123","1.452488","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"124","1.452844","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"125","1.452869","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"126","1.453221","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"127","1.453236","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"128","1.453598","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"129","1.453614","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"130","1.453973","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"131","1.453983","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"132","1.454348","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"133","1.454365","host","3.1.0","USBCOM","43","SET LINE CODING Request"
"134","1.454973","3.1.0","host","USB","28","URB_CONTROL out"
"135","1.454981","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"136","1.455348","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"137","1.455363","host","3.1.0","USBCOM","36","SET CONTROL LINE STATE Request"
"138","1.455602","3.1.0","host","USB","28","URB_CONTROL out"
"139","1.455643","host","3.1.0","USBCOM","43","SET LINE CODING Request"
"140","1.456223","3.1.0","host","USB","28","URB_CONTROL out"
"141","1.456233","host","3.1.0","USBCOM","36","GET LINE CODING Request"
"142","1.456598","3.1.0","host","USBCOM","35","GET LINE CODING Response"
"143","1.456736","host","3.1.1","USBCOM","118","URB_BULK out"
"144","1.456767","3.1.1","host","USB","27","URB_BULK out"
"145","1.456931","3.1.1","host","USBCOM","156","URB_BULK in"
"146","1.456941","host","3.1.1","USB","27","URB_BULK in"
"147","1.456997","3.1.1","host","USBCOM","29","URB_BULK in"
"148","1.456999","host","3.1.1","USB","27","URB_BULK in"
"149","1.457040","3.1.1","host","USBCOM","45","URB_BULK in"
"150","1.457043","host","3.1.1","USB","27","URB_BULK in"
"151","1.457081","3.1.1","host","USBCOM","29","URB_BULK in"
"152","1.457084","host","3.1.1","USB","27","URB_BULK in"
"153","1.457120","3.1.1","host","USBCOM","39","URB_BULK in"
"154","1.457122","host","3.1.1","USB","27","URB_BULK in"
"155","1.457167","3.1.1","host","USBCOM","29","URB_BULK in"
"156","1.457169","host","3.1.1","USB","27","URB_BULK in"
"157","1.457208","3.1.1","host","USBCOM","50","URB_BULK in"
"158","1.457210","host","3.1.1","USB","27","URB_BULK in"
"159","1.457250","3.1.1","host","USBCOM","29","URB_BULK in"
"160","1.457252","host","3.1.1","USB","27","URB_BULK in"
"161","1.457290","3.1.1","host","USBCOM","49","URB_BULK in"
"162","1.457292","host","3.1.1","USB","27","URB_BULK in"
"163","1.457330","3.1.1","host","USBCOM","29","URB_BULK in"
"164","1.457332","host","3.1.1","USB","27","URB_BULK in"
"165","1.457374","3.1.1","host","USBCOM","56","URB_BULK in"
"166","1.457376","host","3.1.1","USB","27","URB_BULK in"
"167","1.457422","3.1.1","host","USBCOM","29","URB_BULK in"
"168","1.457424","host","3.1.1","USB","27","URB_BULK in"
"169","1.457458","3.1.1","host","USBCOM","31","URB_BULK in"
"170","1.457460","host","3.1.1","USB","27","URB_BULK in"
"171","1.457503","3.1.1","host","USBCOM","29","URB_BULK in"
"172","1.457505","host","3.1.1","USB","27","URB_BULK in"
"173","1.457541","3.1.1","host","USBCOM","58","URB_BULK in"
"174","1.457543","host","3.1.1","USB","27","URB_BULK in"
"175","1.457582","3.1.1","host","USBCOM","29","URB_BULK in"
"176","1.457584","host","3.1.1","USB","27","URB_BULK in"
"177","1.457624","3.1.1","host","USBCOM","55","URB_BULK in"
"178","1.457626","host","3.1.1","USB","27","URB_BULK in"
"179","3.615282","3.1.5","host","USB","30","URB_INTERRUPT in"
"180","3.615300","host","3.1.5","USB","27","URB_INTERRUPT in"
"181","3.619275","3.1.5","host","USB","30","URB_INTERRUPT in"
"182","3.619282","host","3.1.5","USB","27","URB_INTERRUPT in"
"183","3.619291","3.1.1","host","USBCOM","29","URB_BULK in"
"184","3.619303","host","3.1.1","USB","27","URB_BULK in"
"185","3.619324","3.1.1","host","USBCOM","32","URB_BULK in"
"186","3.619326","host","3.1.1","USB","27","URB_BULK in"
"187","3.672845","host","3.1.1","USBCOM","19254","URB_BULK out"
"188","3.673032","3.1.1","host","USBCOM","29","URB_BULK in"
"189","3.673046","host","3.1.1","USB","27","URB_BULK in"
"190","3.673130","3.1.1","host","USBCOM","31","URB_BULK in"
"191","3.673134","host","3.1.1","USB","27","URB_BULK in"
"192","3.676117","3.1.1","host","USB","27","URB_BULK out"
"193","3.702833","host","3.1.1","USBCOM","38","URB_BULK out"
"194","3.702900","3.1.1","host","USB","27","URB_BULK out"
"195","3.702938","3.1.1","host","USBCOM","29","URB_BULK in"
"196","3.702946","host","3.1.1","USB","27","URB_BULK in"
"197","3.702978","3.1.1","host","USBCOM","31","URB_BULK in"
"198","3.702981","host","3.1.1","USB","27","URB_BULK in"
"199","3.931303","3.1.5","host","USB","30","URB_INTERRUPT in"
"200","3.931324","host","3.1.5","USB","27","URB_INTERRUPT in"
"201","3.935289","3.1.5","host","USB","30","URB_INTERRUPT in"
"202","3.935300","host","3.1.5","USB","27","URB_INTERRUPT in"
"203","3.935317","3.1.1","host","USBCOM","29","URB_BULK in"
"204","3.935332","host","3.1.1","USB","27","URB_BULK in"
"205","3.935359","3.1.1","host","USBCOM","32","URB_BULK in"
"206","3.935363","host","3.1.1","USB","27","URB_BULK in"


// MY CODE BELOW HERE //

// main.rs //
mod loupedeck;
mod constants;

use loupedeck::*;
use tokio::time;

#[tokio::main]
async fn main() {
    let mut device = loupedeck::Device::new("COM4".to_string());
    device.connect().await.expect("Failed to connect to loupedeck");

    start(device);

    time::sleep(time::Duration::from_secs(50000)).await
}

pub fn start(mut device: Device) 
{
    //let (tx_pending_send, mut rx_pending_send) = mpsc::channel(10);

    //let event_emitter = device.create_external_event_emitter().unwrap();

    tokio::spawn(async move 
    {
        let mut rx_event = device.tx_event.clone().unwrap().subscribe();

        loop 
        {
            match rx_event.recv().await
            {
                Ok(next_event) => 
                {
                    match next_event 
                    {
                        Event::ButtonPress(ButtonPressEvent 
                        {
                            tx_id,
                            button,
                            dir: PressDirection::Down,
                        }) => 
                        {
                            println!("Button down: {tx_id:?}:{button:?}:{:?}", PressDirection::Down);
                            device.draw_key(button.get_x().into(), button.get_y().into(), vec![200; 80 * 80 * 3]).await
                        },
                        Event::ButtonPress(ButtonPressEvent 
                        {
                            tx_id,
                            button,
                            dir: PressDirection::Up,
                        }) => 
                        {
                            println!("Button up: {tx_id:?}:{button:?}:{:?}", PressDirection::Up);
                        },
                        event => 
                        {
                            println!("Unhandled event: {event:?}");
                        }
                    }
                }
                Err(err) => 
                {
                    eprintln!("{err:?}");
                }
            }
        }
    });
}

// loupedeck.rs //
use raqote::DrawTarget;
use std::collections::HashSet;
use std::io::prelude::*;
use std::io::Result;
use tokio::runtime::Runtime;
use tokio::sync::broadcast;
use tokio::sync::mpsc;
use tokio::sync::oneshot;
use tokio::sync::oneshot::error::RecvError;
use tokio::time;
use tokio_serial::SerialPortBuilderExt;
use tokio_serial::SerialStream;

pub use crate::constants::*;

fn parse_serial_message(message: &[u8]) -> Result<Option<Event>> {
    let header: u16 = u16::from_be_bytes([message[0], message[1]]);

    let message_type = MessageHeader::try_from(header).unwrap();
    let tx_id = message[2];

    match message_type {
        MessageHeader::ButtonPress => {
            let button = Button::try_from(message[3]).expect("Invalid button address");
            let dir = PressDirection::try_from(message[4]).expect("Invalid button direction");
            Ok(Some(Event::ButtonPress(ButtonPressEvent {
                button,
                dir,
                tx_id,
            })))
        }
        MessageHeader::SerialIn => Ok(Some(Event::SerialIn(SerialInEvent {
            tx_id,
            serial_number: String::from_utf8(message[3..].to_vec())
                .unwrap()
                .trim()
                .to_string(),
        }))),
        MessageHeader::VersionIn => Ok(Some(Event::VersionIn(VersionInEvent {
            tx_id,
            version: format!("{}.{}.{}", message[3], message[4], message[5]).to_string(),
        }))),
        MessageHeader::ConfirmFrameBuffer => Ok(Some(Event::ConfirmFrameBufferIn(
            ConfirmFrameBufferInEvent { tx_id },
        ))),
        MessageHeader::DrawIn => Ok(Some(Event::DrawIn(DrawInEvent { tx_id }))),
        // MessageHeader::WriteFrameBuffer => todo!(),
        // MessageHeader::Confirm => todo!(),
        // MessageHeader::SerialOut => todo!(),
        // MessageHeader::VersionOut => todo!(),
        // MessageHeader::Tick => todo!(),
        // MessageHeader::SetBrightness => todo!(),
        // MessageHeader::Reset => todo!(),
        // MessageHeader::DrawOut => todo!(),
        // MessageHeader::SetColor => todo!(),
        // MessageHeader::MCU => todo!(),
        _ => Ok(Some(Event::Other(FallbackEvent { tx_id }))),
    }
}

fn get_tx_id(evt: Event) -> Option<u8> {
    match evt {
        Event::ButtonPress(ButtonPressEvent { tx_id, .. }) => Some(tx_id),
        Event::Other(FallbackEvent { tx_id }) => Some(tx_id),
        Event::SerialIn(SerialInEvent { tx_id, .. }) => Some(tx_id),
        Event::VersionIn(VersionInEvent { tx_id, .. }) => Some(tx_id),
        Event::ConfirmFrameBufferIn(ConfirmFrameBufferInEvent { tx_id }) => Some(tx_id),
        Event::DrawIn(DrawInEvent { tx_id }) => Some(tx_id),
        // _ => panic!("Invalid event"),
    }
}

const WS_UPGRADE_HEADER: &str = "GET /index.html
HTTP/1.1
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: 123abc

";

const WS_UPGRADE_RESPONSE: &str = "HTTP/1.1";

#[derive(Debug, Clone)]
pub struct DeviceInfo {
    _serial: String,
    _version: String,
}

pub struct Device {
    pub port: String,
    tx_pending_send: Option<mpsc::Sender<Vec<u8>>>,
    pub tx_event: Option<broadcast::Sender<Event>>,
    next_tx_id: u8,
}

fn construct_draw_buffer_payload(
    screen: Screen,
    x: u16,
    y: u16,
    width: u16,
    height: u16,
    buffer: &[u8],
) -> Result<Vec<u8>> {
    if (width * height * 3) as usize != buffer.len() {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidInput,
            format!("Invalid buffer length. Got: {}, Expected: {}", width * height * 2, buffer.len()),
        ));
    }

    let mut buff = Vec::new();
    buff.append(&mut Vec::from(screen));
    buff.append(&mut x.to_be_bytes().to_vec());
    buff.append(&mut y.to_be_bytes().to_vec());
    buff.append(&mut width.to_be_bytes().to_vec());
    buff.append(&mut height.to_be_bytes().to_vec());
    buff.append(&mut buffer.to_vec());

    return Ok(buff);
}

//
// 82 ff 00 00 00 00 00 00 3f 55 00 00 00 00 ff 10 02 00 41 00 00 00 00 00 5a 00 5a

fn is_redraw_event(msg: &[u8]) -> Option<Screen> {
    let mut screen_id: Option<u8> = None;

    if msg.len() > 18 && msg[1] == 0xff && msg[14] == 0xff && msg[15] == 0x10 {
        screen_id = Some(msg[18]);
    } else if msg.len() > 10 && msg[6] == 0xff && msg[7] == 0x10 {
        screen_id = Some(msg[10]);
    }

    if screen_id.is_none() {
        return None;
    }

    return Some(Screen::try_from(screen_id.unwrap()).unwrap());
}

fn construct_basic_message(action: Vec<u8>, data: Vec<u8>) -> Result<Vec<u8>> {
    let mut header: Vec<u8> = Vec::with_capacity(3);
    header.push(action[0]);
    header.push(action[1]);
    header.push(0x01);

    let mut message: Vec<u8> = Vec::with_capacity(header.len() + data.len());
    message.extend_from_slice(&header);
    message.extend_from_slice(&data);

    return Ok(message);
}

fn construct_message_payload(message_buffer: Vec<u8>, tx_id: u8) -> Vec<u8> {
    let mut prefix_buff: Vec<u8>;

    if message_buffer.len() > 0xff {
        prefix_buff = Vec::with_capacity(14);

        for _i in 0..14 {
            prefix_buff.push(0x00);
        }

        prefix_buff[0] = 0x82;
        prefix_buff[1] = 0xFF;

        let offset = 6;
        // println!("Message length: {:?}", message_buffer.len());

        (message_buffer.len() as u32)
            .to_be_bytes()
            .iter()
            .enumerate()
            .for_each(|(i, b)| {
                prefix_buff[offset + i] = *b;
            });

        // prefix_buff[2 + offset] = (len >> 24) as u8;
        // prefix_buff[3 + offset] = (len >> 16) as u8;
        // prefix_buff[4 + offset] = (len >> 8) as u8;
        // prefix_buff[5 + offset] = len as u8;
    } else {
        prefix_buff = Vec::with_capacity(6);

        for _i in 0..6 {
            prefix_buff.push(0x00);
        }

        prefix_buff[0] = 0x82;
        prefix_buff[1] = 0x80 + message_buffer.len() as u8;
    }

    let mut message = Vec::with_capacity(prefix_buff.len() + message_buffer.len());
    message.extend_from_slice(&prefix_buff);
    message.extend_from_slice(&message_buffer);

    message[prefix_buff.len() + 2] = tx_id;

    message
}

// fn to_hex(bytes: &[u8]) -> String {
//     bytes
//         .iter()
//         .map(|b| format!("{:02x}", b))
//         .collect::<Vec<String>>()
//         .join(" ")
// }

#[derive(Debug, Clone)]
pub struct ExternalMessage {
    action: Vec<u8>,
    data: Vec<u8>,
}

impl From<ExternalMessage> for Vec<u8> {
    fn from(external_message: ExternalMessage) -> Vec<u8> {
        let mut header: Vec<u8> = Vec::with_capacity(3);
        header.push(external_message.action[0]);
        header.push(external_message.action[1]);
        header.push(0x01);

        let mut message: Vec<u8> = Vec::with_capacity(header.len() + external_message.data.len());
        message.extend_from_slice(&header);
        message.extend_from_slice(&external_message.data);

        return construct_message_payload(message, 1);
    }
}

#[derive(Debug, Clone)]
pub struct ExternalDeviceEventEmitter {
    tx_event: mpsc::Sender<ExternalMessage>,
}

impl ExternalDeviceEventEmitter {
    fn new(tx_event: mpsc::Sender<ExternalMessage>) -> Self {
        Self { tx_event }
    }

    async fn send_message(&self, message: ExternalMessage) -> Result<()> {
        // println!("Sending message: {:?}", message);
        self.tx_event.send(message).await.unwrap();
        Ok(())
    }

    pub async fn draw_rgb565(
        &self,
        screen: Screen,
        x: u16,
        y: u16,
        width: u16,
        height: u16,
        data: Vec<u8>,
    ) -> Result<()> {
        let buff_res =
            construct_draw_buffer_payload(screen.clone(), x, y, width, height, data.as_slice());

        self.send_message(ExternalMessage {
            action: Vec::from(MessageHeader::WriteFrameBuffer),
            data: buff_res.unwrap(),
        })
        .await.unwrap();

        Ok(())
    }

    pub async fn draw_target(
        &self,
        screen: Screen,
        x: u16,
        y: u16,
        width: u16,
        height: u16,
        target: DrawTarget,
    ) -> Result<()> {
        let draw_vec = convert_draw_target_to_rgb565(target);
        self.draw_rgb565(screen, x, y, width, height, draw_vec)
            .await
    }
}

impl Device {
    pub fn new(port: String) -> Device {
        Device {
            port,
            tx_pending_send: None,
            tx_event: None,
            next_tx_id: 2,
        }
    }

    pub fn create_external_event_emitter(&self) -> Option<ExternalDeviceEventEmitter> {
        let (tx_ext_message, mut rx_ext_message): (
            mpsc::Sender<ExternalMessage>,
            mpsc::Receiver<ExternalMessage>,
        ) = mpsc::channel(10);

        let tx_pending_send = self.tx_pending_send.as_ref().unwrap().clone();

        tokio::spawn(async move {
            loop {
                // Try to write everything we can from the port
                while let Ok(ext_message) = rx_ext_message.try_recv() {
                    let message = Vec::from(ext_message);
                    // println!("Sending external message: {:?}", to_hex(&message));
                    tx_pending_send.send(message).await.unwrap();
                }
            }
        });

        Some(ExternalDeviceEventEmitter::new(tx_ext_message))
    }

    pub async fn connect(&mut self) -> Result<()> {
        println!("Connecting to Loupedeck on port {}", self.port);

        let mut port = tokio_serial::new(self.port.clone(), 9600)
            .open_native_async()
            .expect("Failed to open port");

        println!("Waiting for writable");
        port.writable().await.unwrap();

        port.try_write(WS_UPGRADE_HEADER.as_bytes())
            .expect("Failed to write to port");

        println!("Waiting for readable");
        port.readable().await.unwrap();
        let mut buf = vec![0; 1024];

        port.try_read(buf.as_mut_slice())
            .expect("Failed to read from port");

        let res = String::from_utf8_lossy(&buf);

        if !res.contains(WS_UPGRADE_RESPONSE) {
            return Err(std::io::Error::new(
                std::io::ErrorKind::Other,
                "Failed to upgrade to websocket",
            ));
        }

        // TODO: All of the below should be moved to a better spot, this is AI-generated
        self.get_descriptor(0x01).await?; // Device descriptor
        self.get_descriptor(0x02).await?; // Configuration descriptor
        self.set_configuration().await?;

        self.get_line_coding().await?;
        self.set_line_coding(9600, 0, 0, 8).await?; // Example values
        self.set_control_line_state(0x0003).await?; // DTR and RTS on

        self.set_brightness(100).await?; // Set to full brightness

        self.start_polling(port);

        return Ok(());
    }
    
    pub fn disconnect(&mut self) {
        println!("Disconnecting from loupedeck on port {}", self.port);

        let runtime = tokio::runtime::Handle::current();

        runtime.block_on(async {
            for _ in 0..4 {
                self.send_break(0).await.unwrap();
            }
        });
        // TODO: Find equivalent to this without runtime
        // runtime.shutdown_background();
    
        self.tx_event = None;
        self.tx_pending_send = None;
    }

    pub async fn draw_key(&mut self, key_x: u16, key_y: u16, img: Vec<u8>) {
        let x: u16 = KEY_SIZE * key_x;
        let y: u16 = KEY_SIZE * key_y;
        let width: u16 = 80;
        let height: u16 = 80;

        self.draw_buffer(Screen::Center, x, y, width, height, img.as_slice())
            .await.unwrap();
    }

    pub async fn draw_buffer(
        &mut self,
        screen: Screen,
        x: u16,
        y: u16,
        width: u16,
        height: u16,
        buffer: &[u8],
    ) -> Result<()> {
        let buff_res = construct_draw_buffer_payload(screen.clone(), x, y, width, height, buffer);

        if buff_res.is_err() {
            return Err(buff_res.unwrap_err());
        }

        self.send_message(
            Vec::from(MessageHeader::WriteFrameBuffer),
            buff_res.unwrap(),
            true,
        )
        .await;

        Ok(())
    }

    pub async fn get_info(&mut self) -> Result<DeviceInfo> {
        let serial_evt = self
            .send_message(Vec::from(MessageHeader::SerialOut), vec![], true)
            .await;
        let version_evt = self
            .send_message(Vec::from(MessageHeader::VersionOut), vec![], true)
            .await;

        let mut version_number: Option<String> = None;
        let mut serial: Option<String> = None;

        if serial_evt.is_some() {
            let serial_evt_result = serial_evt.unwrap();
            if serial_evt_result.is_ok() {
                let serial_evt_event = serial_evt_result.unwrap();
                if let Event::SerialIn(SerialInEvent { serial_number, .. }) = serial_evt_event {
                    serial = Some(serial_number);
                }
            }
        }

        if version_evt.is_some() {
            let version_in_result = version_evt.unwrap();
            if version_in_result.is_ok() {
                let version_in_event = version_in_result.unwrap();
                if let Event::VersionIn(VersionInEvent { version, .. }) = version_in_event {
                    version_number = Some(version);
                }
            }
        }

        if version_number.is_none() || serial.is_none() {
            return Err(std::io::Error::new(
                std::io::ErrorKind::Other,
                "Failed to get device info",
            ));
        }

        return Ok(DeviceInfo {
            _serial: serial.unwrap(),
            _version: version_number.unwrap(),
        });
    }

    async fn send_message(
        &mut self,
        action: Vec<u8>,
        data: Vec<u8>,
        expect_event: bool,
    ) -> Option<std::result::Result<Event, RecvError>> {
        let message = construct_basic_message(action, data);
        return self.send(message.unwrap(), expect_event).await;
    }

    async fn send(
        &mut self,
        message_buffer: Vec<u8>,
        expect_event: bool,
    ) -> Option<std::result::Result<Event, RecvError>> {
        let (response_tx, response_rx): (oneshot::Sender<Event>, oneshot::Receiver<Event>) =
            oneshot::channel();

        let mut tx_id: u8 = 0x01;
        if expect_event {
            tx_id = self.next_tx_id;
            self.next_tx_id += 1;
        }

        let tx_pending_send = self.tx_pending_send.as_ref()?.clone();
        let message = construct_message_payload(message_buffer, tx_id);

        if self.tx_event.is_some() && expect_event {
            let mut rx_event = self.tx_event.clone().unwrap().subscribe();

            tokio::spawn(async move {
                while let Ok(res) = rx_event.recv().await {
                    let evt_tx_id = get_tx_id(res.clone());

                    if evt_tx_id.is_some() && evt_tx_id.unwrap() == tx_id {
                        response_tx.send(res).unwrap();
                        break;
                    }
                }
            });
        }

        tokio::spawn(async move {
            tx_pending_send.send(message).await.unwrap();
        });

        if expect_event {
            return Some(response_rx.await);
        } else {
            return None;
        }
    }

    async fn get_descriptor(&mut self, descriptor_type: u8) -> Result<()> {
        let data = vec![descriptor_type, 0x00, 0x00, 0x01, 0x00, 0x00, 0x12, 0x00];
        self.send_message(vec![0x80, 0x06], data, true).await;
        Ok(())
    }

    async fn set_configuration(&mut self) -> Result<()> {
        self.send_message(vec![0x00, 0x09], vec![0x01], true).await;
        Ok(())
    }

    async fn get_line_coding(&mut self) -> Result<()> {
        self.send_message(vec![0x21, 0x34], vec![], true).await;
        Ok(())
    }

    async fn set_line_coding(&mut self, baud_rate: u32, stop_bits: u8, parity: u8, data_bits: u8) -> Result<()> {
        let mut data = baud_rate.to_le_bytes().to_vec();
        data.extend_from_slice(&[stop_bits, parity, data_bits]);
        self.send_message(vec![0x21, 0x20], data, true).await;
        Ok(())
    }

    async fn set_control_line_state(&mut self, control_bits: u16) -> Result<()> {
        self.send_message(vec![0x21, 0x22], control_bits.to_le_bytes().to_vec(), true).await;
        Ok(())
    }

    async fn set_brightness(&mut self, brightness: u8) -> Result<()> {
        self.send_message(vec![0x04, 0x09], vec![brightness], true).await;
        Ok(())
    }

    async fn send_break(&mut self, duration: u16) -> Result<()> {
        self.send_message(vec![0x21, 0x23], duration.to_le_bytes().to_vec(), true).await;
        Ok(())
    }

    fn start_polling(&mut self, mut serial: SerialStream) {
        let (tx_event, _rx_event) = broadcast::channel(10);
        let (tx_pending_send, mut rx_pending_send) = mpsc::channel(100);

        self.tx_pending_send = Some(tx_pending_send.clone());
        self.tx_event = Some(tx_event.clone());

        println!("Starting polling on port {}", self.port);

        tokio::spawn(async move {
            loop {
                // Send any pending messages

                let mut redrawn_screens = HashSet::new();

                // Try to write everything we can from the port
                while let Ok(message) = rx_pending_send.try_recv() {
                    time::sleep(time::Duration::from_millis(2)).await;

                    loop {
                        let write_res = serial.write_all(&message);

                        match write_res {
                            Ok(_) => {
                                if let Some(redraw) = is_redraw_event(message.as_slice()) {
                                    redrawn_screens.insert(redraw);
                                }
                                break;
                            }
                            Err(e) => {
                                println!("Error writing to serial: {:?}", e);
                                break;
                            }
                        }
                    }
                }

                if !redrawn_screens.is_empty() {
                    // Redraw any screens that have been updated
                    for screen in redrawn_screens {
                        let redraw_payload = construct_basic_message(
                            Vec::from(MessageHeader::DrawOut),
                            Vec::from(screen),
                        )
                        .unwrap();

                        let redraw_message = construct_message_payload(redraw_payload, 1);

                        tx_pending_send.send(redraw_message).await.unwrap();
                    }
                }

                loop {
                    let mut single_byte: Vec<u8> = vec![0; 1];
                    let res = serial.try_read(single_byte.as_mut_slice());

                    if res.is_err() {
                        break;
                    }

                    if single_byte[0] == 0x82 {
                        // Found delimiter
                        serial
                            .try_read(single_byte.as_mut_slice())
                            .expect("Found no length data");
                        let length = single_byte[0] as usize;
                        // println!("Found message with length {}", length);
                        let mut data: Vec<u8> = vec![0; length];
                        serial
                            .try_read(data.as_mut_slice())
                            .expect("Found no data!");
                        let event = parse_serial_message(&data);

                        if event.is_ok() {
                            let evt_unrw = event.unwrap();
                            if evt_unrw.is_some() {
                                tx_event.send(evt_unrw.unwrap()).unwrap();
                            }
                        }
                    }
                }

                time::sleep(time::Duration::from_millis(5)).await
            }
        });
    }
}

#[cfg(test)]
mod tests {
    use super::construct_draw_buffer_payload;

    #[test]
    fn it_create_draw_buffer_red_key_payload() {
        let mut half_red: Vec<u8> = Vec::with_capacity(80 * 80 * 2);
        for _i in 0..(80 * 80) {
            half_red.push(0x00);
            half_red.push(0xF8);
        }

        let mut payload = construct_draw_buffer_payload(
            crate::Screen::Center,
            180,
            0,
            80,
            80,
            half_red.as_slice(),
        )
        .expect("Failed to create payload");

        let header = vec![0x00, 0x41, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x5a];

        assert_eq!(header, payload.drain(0..header.len()).collect::<Vec<u8>>());
        // assert_eq!(payload.len(), 16213);
    }
}

pub fn convert_draw_target_to_rgb565(dt: DrawTarget) -> Vec<u8> {
    let mut result: Vec<u8> = Vec::new();

    let draw_data = dt.get_data();
    for px in draw_data {
        let rgb16 = convert_argb888_to_rgb565(*px);
        result.append(&mut rgb16.to_le_bytes().to_vec());
    }

    result
}

fn convert_argb888_to_rgb565(argb: u32) -> u16 {
    let r = ((argb >> 16) & 0xff) as u16;
    let g = ((argb >> 8) & 0xff) as u16;
    let b = (argb & 0xff) as u16;
    ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3)
}

#[cfg(test)]
mod draw_tests {
    use raqote::{DrawOptions, DrawTarget, SolidSource, Source};

    use crate::convert_draw_target_to_rgb565;

    use super::convert_argb888_to_rgb565;

    #[test]
    fn it_converts() {
        assert_eq!(convert_argb888_to_rgb565(0xFF000000), 0);
        assert_eq!(convert_argb888_to_rgb565(0xFFFFFFFF), 0xffff);
        assert_eq!(convert_argb888_to_rgb565(0xFF0000FF), 0x001f);
        assert_eq!(convert_argb888_to_rgb565(0xFFFF0000), 0xf800);
        assert_eq!(convert_argb888_to_rgb565(0xFF00FF00), 0x07e0);
    }

    #[test]
    fn it_works_for_dt_red() {
        let mut dt = DrawTarget::new(1, 1);

        let solid_red: SolidSource =
            SolidSource::from_unpremultiplied_argb(255, 0xFF, 0x00, 0x00);

        dt.fill_rect(
            0.0,
            0.0,
            1.0,
            1.0,
            &Source::Solid(solid_red),
            &DrawOptions::new(),
        );

        assert_eq!(convert_draw_target_to_rgb565(dt), vec![0x00, 0xF8,]);
    }
    #[test]
    fn it_works_for_dt_green() {
        let mut dt = DrawTarget::new(1, 1);

        let solid_green: SolidSource =
            SolidSource::from_unpremultiplied_argb(255, 0x00, 0xFF, 0x00);

        dt.fill_rect(
            0.0,
            0.0,
            1.0,
            1.0,
            &Source::Solid(solid_green),
            &DrawOptions::new(),
        );

        assert_eq!(convert_draw_target_to_rgb565(dt), vec![0xE0, 0x07,]);
    }

    #[test]
    fn it_works_for_dt_blue() {
        let mut dt = DrawTarget::new(1, 1);

        let solid_blue: SolidSource =
            SolidSource::from_unpremultiplied_argb(255, 0x00, 0x00, 0xFF);

        dt.fill_rect(
            0.0,
            0.0,
            1.0,
            1.0,
            &Source::Solid(solid_blue),
            &DrawOptions::new(),
        );

        assert_eq!(convert_draw_target_to_rgb565(dt), vec![0x1F, 0x00]);
    }
}

// constants.rs //
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, PartialEq)]
#[repr(u16)]
pub enum MessageHeader {
    Confirm = 0x0302,
    SerialOut = 0x0303,
    VersionOut = 0x0307,
    Tick = 0x0400,
    SetBrightness = 0x0409,
    ConfirmFrameBuffer = 0x0410,
    ButtonPress = 0x0500,
    Reset = 0x0506,
    DrawOut = 0x050F,
    DrawIn = 0x040F,
    SetColor = 0x0702,
    VersionIn = 0x0c07,
    MCU = 0x180d,
    SerialIn = 0x1f03,
    WriteFrameBuffer = 0xff10,
}

impl TryFrom<u16> for MessageHeader 
{
    type Error = u16;
    fn try_from(value: u16) -> Result<Self, Self::Error> 
    {
        let result = match value 
        {
            0x0302 => Ok(MessageHeader::Confirm),
            0x0303 => Ok(MessageHeader::SerialOut),
            0x0307 => Ok(MessageHeader::VersionOut),
            0x0400 => Ok(MessageHeader::Tick),
            0x0409 => Ok(MessageHeader::SetBrightness),
            0x0410 => Ok(MessageHeader::ConfirmFrameBuffer),
            0x0500 => Ok(MessageHeader::ButtonPress),
            0x050F => Ok(MessageHeader::DrawOut),
            0x040F => Ok(MessageHeader::DrawIn),
            0x0506 => Ok(MessageHeader::Reset),
            0x0702 => Ok(MessageHeader::SetColor),
            0x0c07 => Ok(MessageHeader::VersionIn),
            0x180d => Ok(MessageHeader::MCU),
            0x1f03 => Ok(MessageHeader::SerialIn),
            0xff10 => Ok(MessageHeader::WriteFrameBuffer),
            value => Err(value),
        };
        println!("Message: {result:?}");
        result
    }
}

impl From<MessageHeader> for Vec<u8> {
    fn from(value: MessageHeader) -> Vec<u8> {
        vec![((value.clone() as u16) >> 8) as u8, value.clone() as u8]
    }
}

#[derive(Debug, Serialize, Clone)]
#[repr(u8)]
pub enum Button 
{
    B00 = 27,
    B10 = 28,
    B20 = 29,
    B30 = 30,
    B40 = 31,
    B01 = 32,
    B11 = 33,
    B21 = 34,
    B31 = 35,
    B41 = 36,
    B02 = 37,
    B12 = 38,
    B22 = 39,
    B32 = 40,
    B42 = 41,
}

impl Button
{
    pub fn get_x(&self) -> u8
    {
        match self
        {
            Self::B00 | Self::B01 | Self::B02 => 0,
            Self::B10 | Self::B11 | Self::B12 => 1,
            Self::B20 | Self::B21 | Self::B22 => 2,
            Self::B30 | Self::B31 | Self::B32 => 3,
            Self::B40 | Self::B41 | Self::B42 => 4,
        }
    }

    pub fn get_y(&self) -> u8
    {
        match self
        {
            Self::B00 | Self::B10 | Self::B20 | Self::B30 | Self::B40 => 0,
            Self::B01 | Self::B11 | Self::B21 | Self::B31 | Self::B41 => 1,
            Self::B02 | Self::B12 | Self::B22 | Self::B32 | Self::B42 => 2,
        }
    }
}

impl TryFrom<u8> for Button 
{
    type Error = u8;
    fn try_from(value: u8) -> Result<Self, Self::Error>
    {
        match value 
        {
            27 => Ok(Button::B00),
            28 => Ok(Button::B10),
            29 => Ok(Button::B20),
            30 => Ok(Button::B30),
            31 => Ok(Button::B40),
            32 => Ok(Button::B01),
            33 => Ok(Button::B11),
            34 => Ok(Button::B21),
            35 => Ok(Button::B31),
            36 => Ok(Button::B41),
            37 => Ok(Button::B02),
            38 => Ok(Button::B12),
            39 => Ok(Button::B22),
            40 => Ok(Button::B32),
            41 => Ok(Button::B42),
            value => Err(value),
        }
    }
}

#[derive(Debug, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u16)]
pub enum Screen {
    Left,
    Center,
    Right,
}

impl From<Screen> for u16 
{
    fn from(value: Screen) -> u16 
    {
        match value 
        {
            Screen::Left => 0x004C,
            Screen::Center => 0x0041,
            Screen::Right => 0x0052,
        }
    }
}

impl TryFrom<u8> for Screen 
{
    type Error = u8;
    fn try_from(value: u8) -> Result<Self, Self::Error> 
    {
        match value 
        {
            0x4C => Ok(Screen::Left),
            0x41 => Ok(Screen::Center),
            0x52 => Ok(Screen::Right),
            value => Err(value),
        }
    }
}

impl From<Screen> for Vec<u8> 
{
    fn from(value: Screen) -> Vec<u8> 
    {
        let base = u16::from(value);
        vec![((base.clone() as u16) >> 8) as u8, base.clone() as u8]
    }
}

impl Screen 
{
    pub fn from_x_coor(x: u16) -> Option<Screen> 
    {
        match x 
        {
            0..=60 => Some(Screen::Left),
            61..=420 => Some(Screen::Center),
            421..=480 => Some(Screen::Right),
            _ => None,
        }
    }
}

struct Display {
    id: u16,
    width: u16,
    height: u16,
}

#[derive(Debug, Serialize, Clone)]
#[repr(u8)]
pub enum PressDirection {
    Up = 0x00,
    Down = 0x01,
}

impl TryFrom<u8> for PressDirection 
{
    type Error = u8;
    fn try_from(value: u8) -> Result<Self, Self::Error> 
    {
        match value 
        {
            0x00 => Ok(PressDirection::Down),
            0x01 => Ok(PressDirection::Up),
            value => Err(value),
        }
    }
}

#[derive(Debug, Serialize, Clone)]
pub struct ButtonPressEvent {
    pub tx_id: u8,
    pub button: Button,
    pub dir: PressDirection,
}

#[derive(Debug, Serialize, Clone)]
pub struct FallbackEvent {
    pub tx_id: u8,
}

#[derive(Debug, Serialize, Clone)]
pub struct SerialInEvent {
    pub tx_id: u8,
    pub serial_number: String,
}

#[derive(Debug, Serialize, Clone)]
pub struct ConfirmFrameBufferInEvent {
    pub tx_id: u8,
}

#[derive(Debug, Serialize, Clone)]
pub struct VersionInEvent {
    pub tx_id: u8,
    pub version: String,
}

#[derive(Debug, Serialize, Clone)]
pub struct DrawInEvent {
    pub tx_id: u8,
}

#[derive(Debug, Serialize, Clone)]
pub enum Event {
    ButtonPress(ButtonPressEvent),
    Other(FallbackEvent),
    SerialIn(SerialInEvent),
    VersionIn(VersionInEvent),
    ConfirmFrameBufferIn(ConfirmFrameBufferInEvent),
    DrawIn(DrawInEvent),
}

pub static KEY_SIZE: u16 = 80;

#[derive(Debug, Serialize, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Deserialize)]
pub struct KeyLocation {
    pub x: u8,
    pub y: u8,
}

impl KeyLocation 
{
    pub fn new(x: u8, y: u8) -> KeyLocation 
    {
        KeyLocation { x, y }
    }

    pub fn from_location(raw_x: u16, raw_y: u16) -> KeyLocation 
    {
        // TODO: Mysterious magic number... and might be wrong anyway?
        let x = ((raw_x - 60) / KEY_SIZE) as u8;
        let y = (raw_y / KEY_SIZE) as u8;
        KeyLocation { x, y }
    }
}