gobot.io/x/gobot/v2@v2.1.0/platforms/neurosky/neurosky_driver.go (about)

     1  package neurosky
     2  
     3  import (
     4  	"bytes"
     5  
     6  	"gobot.io/x/gobot/v2"
     7  )
     8  
     9  const (
    10  	// BTSync is the sync code
    11  	BTSync byte = 0xAA
    12  
    13  	// CodeEx Extended code
    14  	CodeEx byte = 0x55
    15  
    16  	// CodeSignalQuality POOR_SIGNAL quality 0-255
    17  	CodeSignalQuality byte = 0x02
    18  
    19  	// CodeAttention ATTENTION eSense 0-100
    20  	CodeAttention byte = 0x04
    21  
    22  	// CodeMeditation MEDITATION eSense 0-100
    23  	CodeMeditation byte = 0x05
    24  
    25  	// CodeBlink BLINK strength 0-255
    26  	CodeBlink byte = 0x16
    27  
    28  	// CodeWave RAW wave value: 2-byte big-endian 2s-complement
    29  	CodeWave byte = 0x80
    30  
    31  	// CodeAsicEEG ASIC EEG POWER 8 3-byte big-endian integers
    32  	CodeAsicEEG byte = 0x83
    33  
    34  	// Extended event
    35  	Extended = "extended"
    36  
    37  	// Signal event
    38  	Signal = "signal"
    39  
    40  	// Attention event
    41  	Attention = "attention"
    42  
    43  	// Meditation event
    44  	Meditation = "meditation"
    45  
    46  	// Blink event
    47  	Blink = "blink"
    48  
    49  	// Wave event
    50  	Wave = "wave"
    51  
    52  	// EEG event
    53  	EEG = "eeg"
    54  
    55  	// Error event
    56  	Error = "error"
    57  )
    58  
    59  // Driver is the Gobot Driver for the Mindwave
    60  type Driver struct {
    61  	name       string
    62  	connection gobot.Connection
    63  	gobot.Eventer
    64  }
    65  
    66  // EEGData is the EEG raw data returned from the Mindwave
    67  type EEGData struct {
    68  	Delta    int
    69  	Theta    int
    70  	LoAlpha  int
    71  	HiAlpha  int
    72  	LoBeta   int
    73  	HiBeta   int
    74  	LoGamma  int
    75  	MidGamma int
    76  }
    77  
    78  // NewDriver creates a Neurosky Driver
    79  // and adds the following events:
    80  //
    81  //	extended - user's current extended level
    82  //	signal - shows signal strength
    83  //	attention - user's current attention level
    84  //	meditation - user's current meditation level
    85  //	blink - user's current blink level
    86  //	wave - shows wave data
    87  //	eeg - showing eeg data
    88  func NewDriver(a *Adaptor) *Driver {
    89  	n := &Driver{
    90  		name:       "Neurosky",
    91  		connection: a,
    92  		Eventer:    gobot.NewEventer(),
    93  	}
    94  
    95  	n.AddEvent(Extended)
    96  	n.AddEvent(Signal)
    97  	n.AddEvent(Attention)
    98  	n.AddEvent(Meditation)
    99  	n.AddEvent(Blink)
   100  	n.AddEvent(Wave)
   101  	n.AddEvent(EEG)
   102  	n.AddEvent(Error)
   103  
   104  	return n
   105  }
   106  
   107  // Connection returns the Driver's connection
   108  func (n *Driver) Connection() gobot.Connection { return n.connection }
   109  
   110  // Name returns the Driver name
   111  func (n *Driver) Name() string { return n.name }
   112  
   113  // SetName sets the Driver name
   114  func (n *Driver) SetName(name string) { n.name = name }
   115  
   116  // adaptor returns neurosky adaptor
   117  func (n *Driver) adaptor() *Adaptor {
   118  	return n.Connection().(*Adaptor)
   119  }
   120  
   121  // Start creates a go routine to listen from serial port
   122  // and parse buffer readings
   123  func (n *Driver) Start() (err error) {
   124  	go func() {
   125  		for {
   126  			buff := make([]byte, 1024)
   127  			_, err := n.adaptor().sp.Read(buff[:])
   128  			if err != nil {
   129  				n.Publish(n.Event("error"), err)
   130  			} else {
   131  				n.parse(bytes.NewBuffer(buff))
   132  			}
   133  		}
   134  	}()
   135  	return
   136  }
   137  
   138  // Halt stops neurosky driver (void)
   139  func (n *Driver) Halt() (err error) { return }
   140  
   141  // parse converts bytes buffer into packets until no more data is present
   142  func (n *Driver) parse(buf *bytes.Buffer) {
   143  	for buf.Len() > 2 {
   144  		b1, _ := buf.ReadByte()
   145  		b2, _ := buf.ReadByte()
   146  		if b1 == BTSync && b2 == BTSync {
   147  			length, _ := buf.ReadByte()
   148  			payload := make([]byte, length)
   149  			buf.Read(payload)
   150  			//checksum, _ := buf.ReadByte()
   151  			buf.Next(1)
   152  			n.parsePacket(bytes.NewBuffer(payload))
   153  		}
   154  	}
   155  }
   156  
   157  // parsePacket publishes event according to data parsed
   158  func (n *Driver) parsePacket(buf *bytes.Buffer) {
   159  	for buf.Len() > 0 {
   160  		b, _ := buf.ReadByte()
   161  		switch b {
   162  		case CodeEx:
   163  			n.Publish(n.Event("extended"), nil)
   164  		case CodeSignalQuality:
   165  			ret, _ := buf.ReadByte()
   166  			n.Publish(n.Event("signal"), ret)
   167  		case CodeAttention:
   168  			ret, _ := buf.ReadByte()
   169  			n.Publish(n.Event("attention"), ret)
   170  		case CodeMeditation:
   171  			ret, _ := buf.ReadByte()
   172  			n.Publish(n.Event("meditation"), ret)
   173  		case CodeBlink:
   174  			ret, _ := buf.ReadByte()
   175  			n.Publish(n.Event("blink"), ret)
   176  		case CodeWave:
   177  			buf.Next(1)
   178  			var ret = make([]byte, 2)
   179  			buf.Read(ret)
   180  			n.Publish(n.Event("wave"), int16(ret[0])<<8|int16(ret[1]))
   181  		case CodeAsicEEG:
   182  			ret := make([]byte, 25)
   183  			i, _ := buf.Read(ret)
   184  			if i == 25 {
   185  				n.Publish(n.Event("eeg"), n.parseEEG(ret))
   186  			}
   187  		}
   188  	}
   189  }
   190  
   191  // parseEEG returns data converted into EEG map
   192  func (n *Driver) parseEEG(data []byte) EEGData {
   193  	return EEGData{
   194  		Delta:    n.parse3ByteInteger(data[0:3]),
   195  		Theta:    n.parse3ByteInteger(data[3:6]),
   196  		LoAlpha:  n.parse3ByteInteger(data[6:9]),
   197  		HiAlpha:  n.parse3ByteInteger(data[9:12]),
   198  		LoBeta:   n.parse3ByteInteger(data[12:15]),
   199  		HiBeta:   n.parse3ByteInteger(data[15:18]),
   200  		LoGamma:  n.parse3ByteInteger(data[18:21]),
   201  		MidGamma: n.parse3ByteInteger(data[21:25]),
   202  	}
   203  }
   204  
   205  func (n *Driver) parse3ByteInteger(data []byte) int {
   206  	return ((int(data[0]) << 16) |
   207  		(((1 << 16) - 1) & (int(data[1]) << 8)) |
   208  		(((1 << 8) - 1) & int(data[2])))
   209  }