1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
use crate::base::{ErrorCode, HasErrorCode};
use crate::{
    error, Endian, ErrorCodeReaderExt, ErrorCodeWriterExt,
    HasFixedCommandId, IsRequest, IsResponse, IsValidResponseFor,
    MessageExt, ReadExt, ReadFromPayload, Result, TryFromResponse,
    WithFixedPayloadLength, WriteExt,
};
use snafu::ensure;
use std::io::{Read, Write};

#[derive(Clone, Debug, PartialEq)]
pub struct Request {
    pub values: Vec<u16>,
}

impl IsRequest for Request {
    type Response = Response;
}

impl From<Request> for super::Request {
    fn from(m: Request) -> Self {
        super::Request::UploadJob(m)
    }
}

impl Request {
    const ADDITIONAL_FIXED_PAYLOAD_LENGTH: u16 = u16::FIXED_PAYLOAD_LENGTH;

    fn verify_payload_length(received: u16, required: u16) -> Result<()> {
        ensure!(
            required == received,
            error::InvalidPayloadLength {
                message_type: "upload_job_response",
                received,
                required
            }
        );
        Ok(())
    }
}

impl HasFixedCommandId for Request {
    const COMMAND_ID: u16 = 0x2808;
}

impl MessageExt for Request {
    fn payload_length(&self) -> u16 {
        Self::ADDITIONAL_FIXED_PAYLOAD_LENGTH
            + u16::FIXED_PAYLOAD_LENGTH * self.values.len() as u16
    }

    fn write_payload(&self, w: &mut dyn Write) -> Result<()> {
        w.write_u16::<Endian>(self.values.len() as u16)?;
        for value in &self.values {
            w.write_u16::<Endian>(*value)?;
        }
        Ok(())
    }
}

impl ReadFromPayload for Request {
    fn read_from_payload<R: Read>(
        r: &mut R,
        payload_length: u16,
    ) -> Result<Self> {
        let count = r.read_u16::<Endian>()?;
        let required_payload_length = Self::ADDITIONAL_FIXED_PAYLOAD_LENGTH
            + count as u16 * u16::FIXED_PAYLOAD_LENGTH;

        Self::verify_payload_length(
            payload_length,
            required_payload_length,
        )?;
        let mut values = Vec::new();
        for _ in 0..count {
            values.push(r.read_u16::<Endian>()?);
        }
        Ok(Self { values })
    }
}

#[cfg(test)]
mod test_request {
    use super::*;

    #[test]
    fn write_to_empty() {
        let mut buffer = Vec::new();
        let options: u8 = 0x45;
        let sequence: u8 = 0x93;

        let values = Vec::new();

        let message = Request { values };
        message.write_to(&mut buffer, options, sequence).unwrap();
        assert_eq!(
            buffer,
            [
                0x45, // options
                0x93, // sequence
                0x08, // command lower byte
                0x28, // command upper byte
                0x02, // length lower byte
                0x00, // length upper byte
                0x00, // command count lower byte
                0x00, // command count upper byte
            ]
        );
    }

    #[test]
    fn write_to_single_item() {
        let mut buffer = Vec::new();
        let options: u8 = 0x45;
        let sequence: u8 = 0x93;

        let values = vec![0x7542];

        let length = {
            let fixed = 4u16;
            let per_value = 9u16;
            let value_count = 1u16;
            fixed + per_value * value_count
        };
        assert_eq!(length, 0x000D);
        assert_eq!(0x000D, 13);

        let message = Request { values };
        message.write_to(&mut buffer, options, sequence).unwrap();
        assert_eq!(
            buffer,
            vec![
                0x45, // options
                0x93, // sequence
                0x08, // command lower byte
                0x28, // command upper byte
                0x04, // length lower byte
                0x00, // length upper byte
                0x01, // command count lower byte
                0x00, // command count upper byte
                0x42, // command 0 lower byte
                0x75, // command 0 upper byte
            ]
        );
    }

    #[test]
    fn write_to_with_u16_required_length() {
        let mut buffer = Vec::new();
        let options: u8 = 0x45;
        let sequence: u8 = 0x93;

        let values = vec![
            0x1122, 0x3344, 0x5566, 0x7788, 0x9900, 0x1122, 0x3344,
            0x5566, 0x7788, 0x9900, 0x1122, 0x3344, 0x5566, 0x7788,
            0x9900, 0x1122, 0x3344, 0x5566, 0x7788, 0x9900, 0x1122,
            0x3344, 0x5566, 0x7788, 0x9900, 0x1122, 0x3344, 0x5566,
            0x7788, 0x9900, 0x1122, 0x3344, 0x5566, 0x7788, 0x9900,
            0x1122, 0x3344, 0x5566, 0x7788, 0x9900, 0x1122, 0x3344,
            0x5566, 0x7788, 0x9900, 0x1122, 0x3344, 0x5566, 0x7788,
            0x9900, // 50
            //
            0x1122, 0x3344, 0x5566, 0x7788, 0x9900, 0x1122, 0x3344, 0x5566,
            0x7788, 0x9900, 0x1122, 0x3344, 0x5566, 0x7788, 0x9900,
            0x1122, 0x3344, 0x5566, 0x7788, 0x9900, 0x1122, 0x3344,
            0x5566, 0x7788, 0x9900, 0x1122, 0x3344, 0x5566, 0x7788,
            0x9900, 0x1122, 0x3344, 0x5566, 0x7788, 0x9900, 0x1122,
            0x3344, 0x5566, 0x7788, 0x9900, 0x1122, 0x3344, 0x5566,
            0x7788, 0x9900, 0x1122, 0x3344, 0x5566, 0x7788, 0x9900,
            // 100
            //
            0x1122, 0x3344, 0x5566, 0x7788, 0x9900, 0x1122, 0x3344, 0x5566,
            0x7788, 0x9900, 0x1122, 0x3344, 0x5566, 0x7788, 0x9900,
            0x1122, 0x3344, 0x5566, 0x7788, 0x9900, 0x1122, 0x3344,
            0x5566, 0x7788, 0x9900, 0x1122, 0x3344, 0x5566, 0x7788,
            0x9900, 0x1122, 0x3344, 0x5566, 0x7788, 0x9900, 0x1122,
            0x3344, 0x5566, 0x7788, 0x9900, 0x1122, 0x3344, 0x5566,
            0x7788, 0x9900, 0x1122, 0x3344, 0x5566, 0x7788, 0x9900,
            // 150
            //
            0x1122, 0x3344, 0x5566, 0x7788, 0x9900, 0x1122, 0x3344, 0x5566,
            0x7788, 0x9900, 0x1122, 0x3344, 0x5566, 0x7788, 0x9900,
            0x1122, 0x3344, 0x5566, 0x7788, 0x9900, 0x1122, 0x3344,
            0x5566, 0x7788, 0x9900, 0x1122, 0x3344, 0x5566, 0x7788,
            0x9900, 0x1122, 0x3344, 0x5566, 0x7788, 0x9900, 0x1122,
            0x3344, 0x5566, 0x7788, 0x9900, 0x1122, 0x3344, 0x5566,
            0x7788, 0x9900, 0x1122, 0x3344, 0x5566, 0x7788, 0x9900,
            // 200
            //
            0x1122, 0x3344, 0x5566, 0x7788, 0x9900, 0x1122, 0x3344, 0x5566,
            0x7788, 0x9900, 0x1122, 0x3344, 0x5566, 0x7788, 0x9900,
            0x1122, 0x3344, 0x5566, 0x7788, 0x9900, 0x1122, 0x3344,
            0x5566, 0x7788, 0x9900, 0x1122, 0x3344, 0x5566, 0x7788,
            0x9900, 0x1122, 0x3344, 0x5566, 0x7788, 0x9900, 0x1122,
            0x3344, 0x5566, 0x7788, 0x9900, 0x1122, 0x3344, 0x5566,
            0x7788, 0x9900, 0x1122, 0x3344, 0x5566, 0x7788, 0x9900,
            // 250
            //
            0x1122, 0x3344, 0x5566, 0x7788, 0x9900, 0x1122, 0x3344, 0x5566,
            0x7788, 0x9900,
            // 260
        ];

        let length = {
            let fixed = 2u16;
            let per_chunk = 2u16;
            let chunk_count = 258u16;
            fixed + per_chunk * chunk_count
        };
        assert_eq!(length, 0x206u16);
        assert_eq!(0x206u16, 518u16);

        assert_eq!(258u16, 0x0102u16);

        let message = Request { values };
        message.write_to(&mut buffer, options, sequence).unwrap();
        assert_eq!(
            buffer,
            vec![
                0x45, // options
                0x93, // sequence
                0x08, // command lower byte
                0x28, // command upper byte
                0x0A, // length lower byte
                0x02, // length upper byte
                0x04, // command count lower byte
                0x01, // command count upper byte
                //
                0x22, // command chunk 0 lower byte
                0x11, // command chunk 0 upper byte
                0x44, // command chunk 1 lower byte
                0x33, // command chunk 1 upper byte
                0x66, // command chunk 2 lower byte
                0x55, // command chunk 2 upper byte
                0x88, // command chunk 3 lower byte
                0x77, // command chunk 3 upper byte
                0x00, // command chunk 4 lower byte
                0x99, // command chunk 4 upper byte
                //
                0x22, // command chunk 5 lower byte
                0x11, // command chunk 5 upper byte
                0x44, // command chunk 6 lower byte
                0x33, // command chunk 6 upper byte
                0x66, // command chunk 7 lower byte
                0x55, // command chunk 7 upper byte
                0x88, // command chunk 8 lower byte
                0x77, // command chunk 8 upper byte
                0x00, // command chunk 9 lower byte
                0x99, // command chunk 9 upper byte
                //
                0x22, // command chunk 10 lower byte
                0x11, // command chunk 10 upper byte
                0x44, // command chunk 11 lower byte
                0x33, // command chunk 11 upper byte
                0x66, // command chunk 12 lower byte
                0x55, // command chunk 12 upper byte
                0x88, // command chunk 13 lower byte
                0x77, // command chunk 13 upper byte
                0x00, // command chunk 14 lower byte
                0x99, // command chunk 14 upper byte
                //
                0x22, // command chunk 15 lower byte
                0x11, // command chunk 15 upper byte
                0x44, // command chunk 16 lower byte
                0x33, // command chunk 16 upper byte
                0x66, // command chunk 17 lower byte
                0x55, // command chunk 17 upper byte
                0x88, // command chunk 18 lower byte
                0x77, // command chunk 18 upper byte
                0x00, // command chunk 19 lower byte
                0x99, // command chunk 19 upper byte
                //
                0x22, // command chunk 20 lower byte
                0x11, // command chunk 20 upper byte
                0x44, // command chunk 21 lower byte
                0x33, // command chunk 21 upper byte
                0x66, // command chunk 22 lower byte
                0x55, // command chunk 22 upper byte
                0x88, // command chunk 23 lower byte
                0x77, // command chunk 23 upper byte
                0x00, // command chunk 24 lower byte
                0x99, // command chunk 24 upper byte
                //
                0x22, // command chunk 25 lower byte
                0x11, // command chunk 25 upper byte
                0x44, // command chunk 26 lower byte
                0x33, // command chunk 26 upper byte
                0x66, // command chunk 27 lower byte
                0x55, // command chunk 27 upper byte
                0x88, // command chunk 28 lower byte
                0x77, // command chunk 28 upper byte
                0x00, // command chunk 29 lower byte
                0x99, // command chunk 29 upper byte
                //
                0x22, // command chunk 30 lower byte
                0x11, // command chunk 30 upper byte
                0x44, // command chunk 31 lower byte
                0x33, // command chunk 31 upper byte
                0x66, // command chunk 32 lower byte
                0x55, // command chunk 32 upper byte
                0x88, // command chunk 33 lower byte
                0x77, // command chunk 33 upper byte
                0x00, // command chunk 34 lower byte
                0x99, // command chunk 34 upper byte
                //
                0x22, // command chunk 35 lower byte
                0x11, // command chunk 35 upper byte
                0x44, // command chunk 36 lower byte
                0x33, // command chunk 36 upper byte
                0x66, // command chunk 37 lower byte
                0x55, // command chunk 37 upper byte
                0x88, // command chunk 38 lower byte
                0x77, // command chunk 38 upper byte
                0x00, // command chunk 39 lower byte
                0x99, // command chunk 39 upper byte
                //
                0x22, // command chunk 40 lower byte
                0x11, // command chunk 40 upper byte
                0x44, // command chunk 41 lower byte
                0x33, // command chunk 41 upper byte
                0x66, // command chunk 42 lower byte
                0x55, // command chunk 42 upper byte
                0x88, // command chunk 43 lower byte
                0x77, // command chunk 43 upper byte
                0x00, // command chunk 44 lower byte
                0x99, // command chunk 44 upper byte
                //
                0x22, // command chunk 45 lower byte
                0x11, // command chunk 45 upper byte
                0x44, // command chunk 46 lower byte
                0x33, // command chunk 46 upper byte
                0x66, // command chunk 47 lower byte
                0x55, // command chunk 47 upper byte
                0x88, // command chunk 48 lower byte
                0x77, // command chunk 48 upper byte
                0x00, // command chunk 49 lower byte
                0x99, // command chunk 49 upper byte
                //
                0x22, // command chunk 50 lower byte
                0x11, // command chunk 50 upper byte
                0x44, // command chunk 51 lower byte
                0x33, // command chunk 51 upper byte
                0x66, // command chunk 52 lower byte
                0x55, // command chunk 52 upper byte
                0x88, // command chunk 53 lower byte
                0x77, // command chunk 53 upper byte
                0x00, // command chunk 54 lower byte
                0x99, // command chunk 54 upper byte
                //
                0x22, // command chunk 55 lower byte
                0x11, // command chunk 55 upper byte
                0x44, // command chunk 56 lower byte
                0x33, // command chunk 56 upper byte
                0x66, // command chunk 57 lower byte
                0x55, // command chunk 57 upper byte
                0x88, // command chunk 58 lower byte
                0x77, // command chunk 58 upper byte
                0x00, // command chunk 59 lower byte
                0x99, // command chunk 59 upper byte
                //
                0x22, // command chunk 60 lower byte
                0x11, // command chunk 60 upper byte
                0x44, // command chunk 61 lower byte
                0x33, // command chunk 61 upper byte
                0x66, // command chunk 62 lower byte
                0x55, // command chunk 62 upper byte
                0x88, // command chunk 63 lower byte
                0x77, // command chunk 63 upper byte
                0x00, // command chunk 64 lower byte
                0x99, // command chunk 64 upper byte
                //
                0x22, // command chunk 65 lower byte
                0x11, // command chunk 65 upper byte
                0x44, // command chunk 66 lower byte
                0x33, // command chunk 66 upper byte
                0x66, // command chunk 67 lower byte
                0x55, // command chunk 67 upper byte
                0x88, // command chunk 68 lower byte
                0x77, // command chunk 68 upper byte
                0x00, // command chunk 69 lower byte
                0x99, // command chunk 69 upper byte
                //
                0x22, // command chunk 70 lower byte
                0x11, // command chunk 70 upper byte
                0x44, // command chunk 71 lower byte
                0x33, // command chunk 71 upper byte
                0x66, // command chunk 72 lower byte
                0x55, // command chunk 72 upper byte
                0x88, // command chunk 73 lower byte
                0x77, // command chunk 73 upper byte
                0x00, // command chunk 74 lower byte
                0x99, // command chunk 74 upper byte
                //
                0x22, // command chunk 75 lower byte
                0x11, // command chunk 75 upper byte
                0x44, // command chunk 76 lower byte
                0x33, // command chunk 76 upper byte
                0x66, // command chunk 77 lower byte
                0x55, // command chunk 77 upper byte
                0x88, // command chunk 78 lower byte
                0x77, // command chunk 78 upper byte
                0x00, // command chunk 79 lower byte
                0x99, // command chunk 79 upper byte
                //
                0x22, // command chunk 80 lower byte
                0x11, // command chunk 80 upper byte
                0x44, // command chunk 81 lower byte
                0x33, // command chunk 81 upper byte
                0x66, // command chunk 82 lower byte
                0x55, // command chunk 82 upper byte
                0x88, // command chunk 83 lower byte
                0x77, // command chunk 83 upper byte
                0x00, // command chunk 84 lower byte
                0x99, // command chunk 84 upper byte
                //
                0x22, // command chunk 85 lower byte
                0x11, // command chunk 85 upper byte
                0x44, // command chunk 86 lower byte
                0x33, // command chunk 86 upper byte
                0x66, // command chunk 87 lower byte
                0x55, // command chunk 87 upper byte
                0x88, // command chunk 88 lower byte
                0x77, // command chunk 88 upper byte
                0x00, // command chunk 89 lower byte
                0x99, // command chunk 89 upper byte
                //
                0x22, // command chunk 90 lower byte
                0x11, // command chunk 90 upper byte
                0x44, // command chunk 91 lower byte
                0x33, // command chunk 91 upper byte
                0x66, // command chunk 92 lower byte
                0x55, // command chunk 92 upper byte
                0x88, // command chunk 93 lower byte
                0x77, // command chunk 93 upper byte
                0x00, // command chunk 94 lower byte
                0x99, // command chunk 94 upper byte
                //
                0x22, // command chunk 95 lower byte
                0x11, // command chunk 95 upper byte
                0x44, // command chunk 96 lower byte
                0x33, // command chunk 96 upper byte
                0x66, // command chunk 97 lower byte
                0x55, // command chunk 97 upper byte
                0x88, // command chunk 98 lower byte
                0x77, // command chunk 98 upper byte
                0x00, // command chunk 99 lower byte
                0x99, // command chunk 99 upper byte
                //
                0x22, // command chunk 100 lower byte
                0x11, // command chunk 100 upper byte
                0x44, // command chunk 101 lower byte
                0x33, // command chunk 101 upper byte
                0x66, // command chunk 102 lower byte
                0x55, // command chunk 102 upper byte
                0x88, // command chunk 103 lower byte
                0x77, // command chunk 103 upper byte
                0x00, // command chunk 104 lower byte
                0x99, // command chunk 104 upper byte
                //
                0x22, // command chunk 105 lower byte
                0x11, // command chunk 105 upper byte
                0x44, // command chunk 106 lower byte
                0x33, // command chunk 106 upper byte
                0x66, // command chunk 107 lower byte
                0x55, // command chunk 107 upper byte
                0x88, // command chunk 108 lower byte
                0x77, // command chunk 108 upper byte
                0x00, // command chunk 109 lower byte
                0x99, // command chunk 109 upper byte
                //
                0x22, // command chunk 110 lower byte
                0x11, // command chunk 110 upper byte
                0x44, // command chunk 111 lower byte
                0x33, // command chunk 111 upper byte
                0x66, // command chunk 112 lower byte
                0x55, // command chunk 112 upper byte
                0x88, // command chunk 113 lower byte
                0x77, // command chunk 113 upper byte
                0x00, // command chunk 114 lower byte
                0x99, // command chunk 114 upper byte
                //
                0x22, // command chunk 115 lower byte
                0x11, // command chunk 115 upper byte
                0x44, // command chunk 116 lower byte
                0x33, // command chunk 116 upper byte
                0x66, // command chunk 117 lower byte
                0x55, // command chunk 117 upper byte
                0x88, // command chunk 118 lower byte
                0x77, // command chunk 118 upper byte
                0x00, // command chunk 119 lower byte
                0x99, // command chunk 119 upper byte
                //
                0x22, // command chunk 120 lower byte
                0x11, // command chunk 120 upper byte
                0x44, // command chunk 121 lower byte
                0x33, // command chunk 121 upper byte
                0x66, // command chunk 122 lower byte
                0x55, // command chunk 122 upper byte
                0x88, // command chunk 123 lower byte
                0x77, // command chunk 123 upper byte
                0x00, // command chunk 124 lower byte
                0x99, // command chunk 124 upper byte
                //
                0x22, // command chunk 125 lower byte
                0x11, // command chunk 125 upper byte
                0x44, // command chunk 126 lower byte
                0x33, // command chunk 126 upper byte
                0x66, // command chunk 127 lower byte
                0x55, // command chunk 127 upper byte
                0x88, // command chunk 128 lower byte
                0x77, // command chunk 128 upper byte
                0x00, // command chunk 129 lower byte
                0x99, // command chunk 129 upper byte
                //
                0x22, // command chunk 130 lower byte
                0x11, // command chunk 130 upper byte
                0x44, // command chunk 131 lower byte
                0x33, // command chunk 131 upper byte
                0x66, // command chunk 132 lower byte
                0x55, // command chunk 132 upper byte
                0x88, // command chunk 133 lower byte
                0x77, // command chunk 133 upper byte
                0x00, // command chunk 134 lower byte
                0x99, // command chunk 134 upper byte
                //
                0x22, // command chunk 135 lower byte
                0x11, // command chunk 135 upper byte
                0x44, // command chunk 136 lower byte
                0x33, // command chunk 136 upper byte
                0x66, // command chunk 137 lower byte
                0x55, // command chunk 137 upper byte
                0x88, // command chunk 138 lower byte
                0x77, // command chunk 138 upper byte
                0x00, // command chunk 139 lower byte
                0x99, // command chunk 139 upper byte
                //
                0x22, // command chunk 140 lower byte
                0x11, // command chunk 140 upper byte
                0x44, // command chunk 141 lower byte
                0x33, // command chunk 141 upper byte
                0x66, // command chunk 142 lower byte
                0x55, // command chunk 142 upper byte
                0x88, // command chunk 143 lower byte
                0x77, // command chunk 143 upper byte
                0x00, // command chunk 144 lower byte
                0x99, // command chunk 144 upper byte
                //
                0x22, // command chunk 145 lower byte
                0x11, // command chunk 145 upper byte
                0x44, // command chunk 146 lower byte
                0x33, // command chunk 146 upper byte
                0x66, // command chunk 147 lower byte
                0x55, // command chunk 147 upper byte
                0x88, // command chunk 148 lower byte
                0x77, // command chunk 148 upper byte
                0x00, // command chunk 149 lower byte
                0x99, // command chunk 149 upper byte
                //
                0x22, // command chunk 150 lower byte
                0x11, // command chunk 150 upper byte
                0x44, // command chunk 151 lower byte
                0x33, // command chunk 151 upper byte
                0x66, // command chunk 152 lower byte
                0x55, // command chunk 152 upper byte
                0x88, // command chunk 153 lower byte
                0x77, // command chunk 153 upper byte
                0x00, // command chunk 154 lower byte
                0x99, // command chunk 154 upper byte
                //
                0x22, // command chunk 155 lower byte
                0x11, // command chunk 155 upper byte
                0x44, // command chunk 156 lower byte
                0x33, // command chunk 156 upper byte
                0x66, // command chunk 157 lower byte
                0x55, // command chunk 157 upper byte
                0x88, // command chunk 158 lower byte
                0x77, // command chunk 158 upper byte
                0x00, // command chunk 159 lower byte
                0x99, // command chunk 159 upper byte
                //
                0x22, // command chunk 160 lower byte
                0x11, // command chunk 160 upper byte
                0x44, // command chunk 161 lower byte
                0x33, // command chunk 161 upper byte
                0x66, // command chunk 162 lower byte
                0x55, // command chunk 162 upper byte
                0x88, // command chunk 163 lower byte
                0x77, // command chunk 163 upper byte
                0x00, // command chunk 164 lower byte
                0x99, // command chunk 164 upper byte
                //
                0x22, // command chunk 165 lower byte
                0x11, // command chunk 165 upper byte
                0x44, // command chunk 166 lower byte
                0x33, // command chunk 166 upper byte
                0x66, // command chunk 167 lower byte
                0x55, // command chunk 167 upper byte
                0x88, // command chunk 168 lower byte
                0x77, // command chunk 168 upper byte
                0x00, // command chunk 169 lower byte
                0x99, // command chunk 169 upper byte
                //
                0x22, // command chunk 170 lower byte
                0x11, // command chunk 170 upper byte
                0x44, // command chunk 171 lower byte
                0x33, // command chunk 171 upper byte
                0x66, // command chunk 172 lower byte
                0x55, // command chunk 172 upper byte
                0x88, // command chunk 173 lower byte
                0x77, // command chunk 173 upper byte
                0x00, // command chunk 174 lower byte
                0x99, // command chunk 174 upper byte
                //
                0x22, // command chunk 175 lower byte
                0x11, // command chunk 175 upper byte
                0x44, // command chunk 176 lower byte
                0x33, // command chunk 176 upper byte
                0x66, // command chunk 177 lower byte
                0x55, // command chunk 177 upper byte
                0x88, // command chunk 178 lower byte
                0x77, // command chunk 178 upper byte
                0x00, // command chunk 179 lower byte
                0x99, // command chunk 179 upper byte
                //
                0x22, // command chunk 180 lower byte
                0x11, // command chunk 180 upper byte
                0x44, // command chunk 181 lower byte
                0x33, // command chunk 181 upper byte
                0x66, // command chunk 182 lower byte
                0x55, // command chunk 182 upper byte
                0x88, // command chunk 183 lower byte
                0x77, // command chunk 183 upper byte
                0x00, // command chunk 184 lower byte
                0x99, // command chunk 184 upper byte
                //
                0x22, // command chunk 185 lower byte
                0x11, // command chunk 185 upper byte
                0x44, // command chunk 186 lower byte
                0x33, // command chunk 186 upper byte
                0x66, // command chunk 187 lower byte
                0x55, // command chunk 187 upper byte
                0x88, // command chunk 188 lower byte
                0x77, // command chunk 188 upper byte
                0x00, // command chunk 189 lower byte
                0x99, // command chunk 189 upper byte
                //
                0x22, // command chunk 190 lower byte
                0x11, // command chunk 190 upper byte
                0x44, // command chunk 191 lower byte
                0x33, // command chunk 191 upper byte
                0x66, // command chunk 192 lower byte
                0x55, // command chunk 192 upper byte
                0x88, // command chunk 193 lower byte
                0x77, // command chunk 193 upper byte
                0x00, // command chunk 194 lower byte
                0x99, // command chunk 194 upper byte
                //
                0x22, // command chunk 195 lower byte
                0x11, // command chunk 195 upper byte
                0x44, // command chunk 196 lower byte
                0x33, // command chunk 196 upper byte
                0x66, // command chunk 197 lower byte
                0x55, // command chunk 197 upper byte
                0x88, // command chunk 198 lower byte
                0x77, // command chunk 198 upper byte
                0x00, // command chunk 199 lower byte
                0x99, // command chunk 199 upper byte
                //
                0x22, // command chunk 200 lower byte
                0x11, // command chunk 200 upper byte
                0x44, // command chunk 201 lower byte
                0x33, // command chunk 201 upper byte
                0x66, // command chunk 202 lower byte
                0x55, // command chunk 202 upper byte
                0x88, // command chunk 203 lower byte
                0x77, // command chunk 203 upper byte
                0x00, // command chunk 204 lower byte
                0x99, // command chunk 204 upper byte
                //
                0x22, // command chunk 205 lower byte
                0x11, // command chunk 205 upper byte
                0x44, // command chunk 206 lower byte
                0x33, // command chunk 206 upper byte
                0x66, // command chunk 207 lower byte
                0x55, // command chunk 207 upper byte
                0x88, // command chunk 208 lower byte
                0x77, // command chunk 208 upper byte
                0x00, // command chunk 209 lower byte
                0x99, // command chunk 209 upper byte
                //
                0x22, // command chunk 210 lower byte
                0x11, // command chunk 210 upper byte
                0x44, // command chunk 211 lower byte
                0x33, // command chunk 211 upper byte
                0x66, // command chunk 212 lower byte
                0x55, // command chunk 212 upper byte
                0x88, // command chunk 213 lower byte
                0x77, // command chunk 213 upper byte
                0x00, // command chunk 214 lower byte
                0x99, // command chunk 214 upper byte
                //
                0x22, // command chunk 215 lower byte
                0x11, // command chunk 215 upper byte
                0x44, // command chunk 216 lower byte
                0x33, // command chunk 216 upper byte
                0x66, // command chunk 217 lower byte
                0x55, // command chunk 217 upper byte
                0x88, // command chunk 218 lower byte
                0x77, // command chunk 218 upper byte
                0x00, // command chunk 219 lower byte
                0x99, // command chunk 219 upper byte
                //
                0x22, // command chunk 220 lower byte
                0x11, // command chunk 220 upper byte
                0x44, // command chunk 221 lower byte
                0x33, // command chunk 221 upper byte
                0x66, // command chunk 222 lower byte
                0x55, // command chunk 222 upper byte
                0x88, // command chunk 223 lower byte
                0x77, // command chunk 223 upper byte
                0x00, // command chunk 224 lower byte
                0x99, // command chunk 224 upper byte
                //
                0x22, // command chunk 225 lower byte
                0x11, // command chunk 225 upper byte
                0x44, // command chunk 226 lower byte
                0x33, // command chunk 226 upper byte
                0x66, // command chunk 227 lower byte
                0x55, // command chunk 227 upper byte
                0x88, // command chunk 228 lower byte
                0x77, // command chunk 228 upper byte
                0x00, // command chunk 229 lower byte
                0x99, // command chunk 229 upper byte
                //
                0x22, // command chunk 230 lower byte
                0x11, // command chunk 230 upper byte
                0x44, // command chunk 231 lower byte
                0x33, // command chunk 231 upper byte
                0x66, // command chunk 232 lower byte
                0x55, // command chunk 232 upper byte
                0x88, // command chunk 233 lower byte
                0x77, // command chunk 233 upper byte
                0x00, // command chunk 234 lower byte
                0x99, // command chunk 234 upper byte
                //
                0x22, // command chunk 235 lower byte
                0x11, // command chunk 235 upper byte
                0x44, // command chunk 236 lower byte
                0x33, // command chunk 236 upper byte
                0x66, // command chunk 237 lower byte
                0x55, // command chunk 237 upper byte
                0x88, // command chunk 238 lower byte
                0x77, // command chunk 238 upper byte
                0x00, // command chunk 239 lower byte
                0x99, // command chunk 239 upper byte
                //
                0x22, // command chunk 240 lower byte
                0x11, // command chunk 240 upper byte
                0x44, // command chunk 241 lower byte
                0x33, // command chunk 241 upper byte
                0x66, // command chunk 242 lower byte
                0x55, // command chunk 242 upper byte
                0x88, // command chunk 243 lower byte
                0x77, // command chunk 243 upper byte
                0x00, // command chunk 244 lower byte
                0x99, // command chunk 244 upper byte
                //
                0x22, // command chunk 245 lower byte
                0x11, // command chunk 245 upper byte
                0x44, // command chunk 246 lower byte
                0x33, // command chunk 246 upper byte
                0x66, // command chunk 247 lower byte
                0x55, // command chunk 247 upper byte
                0x88, // command chunk 248 lower byte
                0x77, // command chunk 248 upper byte
                0x00, // command chunk 249 lower byte
                0x99, // command chunk 249 upper byte
                //
                0x22, // command chunk 250 lower byte
                0x11, // command chunk 250 upper byte
                0x44, // command chunk 251 lower byte
                0x33, // command chunk 251 upper byte
                0x66, // command chunk 252 lower byte
                0x55, // command chunk 252 upper byte
                0x88, // command chunk 253 lower byte
                0x77, // command chunk 253 upper byte
                0x00, // command chunk 254 lower byte
                0x99, // command chunk 254 upper byte
                //
                0x22, // command chunk 255 lower byte
                0x11, // command chunk 255 upper byte
                0x44, // command chunk 256 lower byte
                0x33, // command chunk 256 upper byte
                0x66, // command chunk 257 lower byte
                0x55, // command chunk 257 upper byte
                0x88, // command chunk 258 lower byte
                0x77, // command chunk 258 upper byte
                0x00, // command chunk 259 lower byte
                0x99, // command chunk 259 upper byte
                      //
            ]
        );
    }

    #[test]
    fn from_payload_empty() {
        let buffer = vec![
            0x00, // command count lower byte
            0x00, // command count upper byte
        ];
        let len = buffer.len() as u16;
        let message =
            Request::read_from_payload(&mut buffer.as_slice(), len)
                .unwrap();
        let values = Vec::new();
        assert_eq!(message, Request { values });
    }
    #[test]
    fn from_payload_single_item() {
        let buffer = vec![
            0x01, // command count lower byte
            0x00, // command count upper byte
            0x26, // command chunk 0 lower byte
            0x94, // command chunk 0 upper byte
        ];
        let len = buffer.len() as u16;
        let message =
            Request::read_from_payload(&mut buffer.as_slice(), len)
                .unwrap();

        let values = vec![0x9426];

        assert_eq!(message, Request { values });
    }
    #[test]
    fn read_from_three_items() {
        let buffer = vec![
            0x03, // command count lower byte
            0x00, // command count upper byte
            0x22, // command chunk 0 lower byte
            0x11, // command chunk 0 upper byte
            0x44, // command chunk 1 lower byte
            0x33, // command chunk 1 upper byte
            0x66, // command chunk 2 lower byte
            0x55, // command chunk 2 upper byte
        ];
        let len = buffer.len() as u16;
        let message =
            Request::read_from_payload(&mut buffer.as_slice(), len)
                .unwrap();

        let values = vec![0x1122, 0x3344, 0x5566];

        assert_eq!(message, Request { values });
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct Response {
    pub error: ErrorCode,
    pub job_slot_index: u16,
}

impl IsResponse for Response {
    type Request = Request;
}

impl IsValidResponseFor for Response {
    fn is_valid_response_for(&self, _request: &Request) -> bool {
        true
    }
}

impl HasErrorCode for Response {
    fn error_code(&self) -> ErrorCode {
        self.error
    }
}

impl TryFromResponse for Response {
    fn try_from_response(r: super::Response) -> Result<Self> {
        if let super::Response::UploadJob(r) = r {
            Ok(r)
        } else {
            error::UnexpectedResponseType.fail()
        }
    }
}

impl From<Response> for super::Response {
    fn from(m: Response) -> Self {
        super::Response::UploadJob(m)
    }
}

impl WithFixedPayloadLength for Response {
    const FIXED_PAYLOAD_LENGTH: u16 =
        ErrorCode::FIXED_PAYLOAD_LENGTH + u16::FIXED_PAYLOAD_LENGTH;
}

impl HasFixedCommandId for Response {
    const COMMAND_ID: u16 = 0x2809;
}

impl MessageExt for Response {
    fn payload_length(&self) -> u16 {
        Self::FIXED_PAYLOAD_LENGTH
    }

    fn write_payload(&self, w: &mut dyn Write) -> Result<()> {
        w.write_error_code(self.error)?;
        w.write_u16::<Endian>(self.job_slot_index)?;
        Ok(())
    }
}

impl ReadFromPayload for Response {
    fn read_from_payload<R: Read>(
        r: &mut R,
        payload_length: u16,
    ) -> Result<Self> {
        Self::verify_payload_length(
            payload_length,
            "upload_job_response",
        )?;
        let error = r.read_error_code()?;
        let job_slot_index = r.read_u16::<Endian>()?;
        Ok(Self {
            error,
            job_slot_index,
        })
    }
}

#[cfg(test)]
mod test_response {
    use super::*;

    #[test]
    fn write_to() {
        let mut buffer = Vec::new();
        let options: u8 = 0x45;
        let sequence: u8 = 0x93;

        let message = Response {
            error: ErrorCode::InvalidState, // 0x0107
            job_slot_index: 0x6413,
        };
        message.write_to(&mut buffer, options, sequence).unwrap();
        assert_eq!(
            buffer,
            [
                0x45, // options
                0x93, // sequence
                0x09, // command lower byte
                0x28, // command upper byte
                0x04, // length lower byte
                0x00, // length upper byte
                0x07, // error lower byte
                0x01, // error upper byte
                0x13, // job_slot_index lower byte
                0x64, // job_slot_index upper byte
            ]
        );
    }

    #[test]
    fn read_from_payload() {
        let buffer = vec![0x07, 0x01, 0x13, 0x64];
        let len = buffer.len() as u16;
        let message =
            Response::read_from_payload(&mut buffer.as_slice(), len)
                .unwrap();
        assert_eq!(
            message,
            Response {
                error: ErrorCode::InvalidState,
                job_slot_index: 0x6413
            }
        );
    }
}