<commit_before>//  Copyright 2016 The goscope Authors
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

package hantek6022be

import (
	"log"

	"github.com/pkg/errors"
	"github.com/zagrodzki/goscope/scope"
)

// Clear the capture buffer and start sampling.
func (h *Scope) startCapture() error {
	if h.stop != nil {
		return nil
	}
	if _, err := h.dev.Control(controlTypeVendor, triggerReq, 0, 0, []byte{0x01}); err != nil {
		return errors.Wrap(err, "Control(trigger on) failed")
	}
	h.stop = make(chan struct{}, 1)
	// HT6022BE has only 2kB buffer onboard. At 16Msps it takes about 60us to fill it up.
	// Request as much data as possible in one go, that way the host does not have
	// to spend time going back and forth between sending commands and receiving data,
	// but just keeps reading data packets.
	// But cap the ep.Read latency below 1/10th of a second to ensure high-ish refresh rate.
	readLen := int(h.sampleRate / 10)
	// round up to nearest 512B
	if readLen%512 != 0 {
		readLen = 512 * (readLen/512 + 1)
	}
	sampleBuf = make([]byte, readLen)
	return nil
}

// Stop sampling.
func (h *Scope) stopCapture() error {
	if h.stop == nil {
		return nil
	}
	h.stop <- struct{}{}
	h.stop = nil
	_, err := h.dev.Control(controlTypeVendor, triggerReq, 0, 0, []byte{0x00})
	return errors.Wrap(err, "Control(trigger off) failed")
}

type reader interface {
	Read([]byte) (int, error)
}

type captureParams struct {
	calibration [2]float64
	scale       [2]float64
}

var sampleBuf []byte

// get samples from USB and send processed to channel.
func (h *Scope) getSamples(ep reader, p captureParams, ch chan<- scope.Data) error {
	num, err := ep.Read(sampleBuf)
	if num != len(sampleBuf) {
		log.Printf("Read %d bytes, buffer lenght %d", num, len(sampleBuf))
	}
	if err != nil {
		return errors.Wrap(err, "Read")
	}
	if num%2 != 0 {
		return errors.Errorf("Read returned %d bytes of data, expected an even number for 2 channels", num)
	}
	samples := [2][]scope.Sample{make([]scope.Sample, num/numChan), make([]scope.Sample, num/numChan)}
	for i := 0; i < num; i++ {
		samples[i%numChan][i/numChan] = scope.Sample((float64(sampleBuf[i]) - p.calibration[i%numChan]) * p.scale[i%numChan])
	}
	ch <- scope.Data{
		Samples: map[scope.ChanID][]scope.Sample{
			ch1ID: samples[ch1Idx],
			ch2ID: samples[ch2Idx],
		},
		Interval: h.sampleRate.Interval(),
	}
	return nil
}

// StartSampling starts processing of USB data.
func (h *Scope) StartSampling() (<-chan scope.Data, func(), error) {
	ep, err := h.dev.OpenEndpoint(bulkConfig, bulkInterface, bulkAlt, bulkEP)
	if err != nil {
		return nil, nil, errors.Wrap(err, "OpenEndpoint")
	}

	params := captureParams{
		calibration: h.getCalibrationData(),
		scale: [2]float64{
			// TODO(sebek): /123 is a very poor approximation.<commit_msg>doh, sampleRate / 10 = 1/20s second worth of samples, because we have two channels at that sample rate.<commit_after>//  Copyright 2016 The goscope Authors
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

package hantek6022be

import (
	"log"

	"github.com/pkg/errors"
	"github.com/zagrodzki/goscope/scope"
)

// Clear the capture buffer and start sampling.
func (h *Scope) startCapture() error {
	if h.stop != nil {
		return nil
	}
	if _, err := h.dev.Control(controlTypeVendor, triggerReq, 0, 0, []byte{0x01}); err != nil {
		return errors.Wrap(err, "Control(trigger on) failed")
	}
	h.stop = make(chan struct{}, 1)
	// HT6022BE has only 2kB buffer onboard. At 16Msps it takes about 60us to fill it up.
	// Request as much data as possible in one go, that way the host does not have
	// to spend time going back and forth between sending commands and receiving data,
	// but just keeps reading data packets.
	// But cap the ep.Read latency below 1/10th of a second to ensure high-ish refresh rate.
	readLen := int(h.sampleRate * numChan / 10)
	// round up to nearest 512B
	if readLen%512 != 0 {
		readLen = 512 * (readLen/512 + 1)
	}
	sampleBuf = make([]byte, readLen)
	return nil
}

// Stop sampling.
func (h *Scope) stopCapture() error {
	if h.stop == nil {
		return nil
	}
	h.stop <- struct{}{}
	h.stop = nil
	_, err := h.dev.Control(controlTypeVendor, triggerReq, 0, 0, []byte{0x00})
	return errors.Wrap(err, "Control(trigger off) failed")
}

type reader interface {
	Read([]byte) (int, error)
}

type captureParams struct {
	calibration [2]float64
	scale       [2]float64
}

var sampleBuf []byte

// get samples from USB and send processed to channel.
func (h *Scope) getSamples(ep reader, p captureParams, ch chan<- scope.Data) error {
	num, err := ep.Read(sampleBuf)
	if num != len(sampleBuf) {
		log.Printf("Read %d bytes, buffer lenght %d", num, len(sampleBuf))
	}
	if err != nil {
		return errors.Wrap(err, "Read")
	}
	if num%numChan != 0 {
		return errors.Errorf("Read returned %d bytes of data, expected an even number for 2 channels", num)
	}
	samples := [2][]scope.Sample{make([]scope.Sample, num/numChan), make([]scope.Sample, num/numChan)}
	for i := 0; i < num; i++ {
		samples[i%numChan][i/numChan] = scope.Sample((float64(sampleBuf[i]) - p.calibration[i%numChan]) * p.scale[i%numChan])
	}
	ch <- scope.Data{
		Samples: map[scope.ChanID][]scope.Sample{
			ch1ID: samples[ch1Idx],
			ch2ID: samples[ch2Idx],
		},
		Interval: h.sampleRate.Interval(),
	}
	return nil
}

// StartSampling starts processing of USB data.
func (h *Scope) StartSampling() (<-chan scope.Data, func(), error) {
	ep, err := h.dev.OpenEndpoint(bulkConfig, bulkInterface, bulkAlt, bulkEP)
	if err != nil {
		return nil, nil, errors.Wrap(err, "OpenEndpoint")
	}

	params := captureParams{
		calibration: h.getCalibrationData(),
		scale: [2]float64{
			// TODO(sebek): /123 is a very poor approximation.
{'fraction_non_alphanumeric': 0.13066150178784267, 'fraction_numerical': 0.02264600715137068, 'mean_word_length': 3.700980392156863, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6690580', 'n_tokens_mistral': 2379, 'n_tokens_neox': 2204, 'n_words': 776}