Instrument Neutral Distributed Interface INDI  2.0.2
indi_shelyak_usis.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2022 Etienne Cochard. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify it
5  under the terms of the GNU General Public License as published by the Free
6  Software Foundation; either version 2 of the License, or (at your option)
7  any later version.
8 
9  This program is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18 
19  The full GNU General Public License is included in this distribution in the
20  file called LICENSE.
21 *******************************************************************************/
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 
28 #include <map>
29 #include <math.h>
30 #include <memory>
31 
32 #include <indicom.h>
33 
34 #include "version.h"
35 #include "indi_shelyak_usis.h"
36 
37 double _atof( const char* in )
38 {
39  char* e;
40  return strtof( in, &e );
41 }
42 
43 static std::unique_ptr<ShelyakDriver> usis(new ShelyakDriver());
44 
45 // :: Driver ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
46 
48 {
49  _guid = 1;
50  _serialPort = -1;
51 
53 }
54 
56 {
57  if ( _serialPort != -1 )
58  {
59  clearProperties( );
60  tty_disconnect( _serialPort );
61  }
62 }
63 
68 bool ShelyakDriver::readConfig( )
69 {
70  auto fname = getSharedFilePath("shelyak_boards.json");
71 
72  try
73  {
74  std::ifstream file( fname );
75  file >> _config;
76  return true;
77  }
78  catch( const std::ifstream::failure &e )
79  {
80  LOGF_ERROR( "File not found: %s", fname.c_str() );
81  return false;
82  }
83  catch( json::exception & )
84  {
85  LOGF_ERROR( "Bad json file format: %s", fname.c_str() );
86  return false;
87  }
88 }
89 
94 bool ShelyakDriver::findBoard( const char* boardName, json* result )
95 {
96  if( !_config.is_object() )
97  {
98  return false;
99  }
100 
101  json boards = _config["boards"];
102  if( !boards.is_array() )
103  {
104  return false;
105  }
106 
107  for( json::iterator it = boards.begin(); it != boards.end(); ++it)
108  {
109 
110  if( !it->is_object() )
111  {
112  continue;
113  }
114 
115  json sig = (*it)["signature"];
116  if( !sig.is_string() )
117  {
118  continue;
119  }
120 
121  std::string s = sig;
122  if( s == boardName )
123  {
124  *result = *it;
125  return true;
126  }
127  }
128 
129  return false;
130 }
131 
132 /* Returns the name of the device. */
134 {
135  return "Shelyak Usis";
136 }
137 
138 /* */
139 bool ShelyakDriver::Connect( )
140 {
141  int rc = TTY_OK;
142  if ( ( rc = tty_connect( serialConnection->port(), 2400, 8, 0, 1, &_serialPort ) ) != TTY_OK )
143  {
144  char errMsg[MAXRBUF];
145  tty_error_msg( rc, errMsg, MAXRBUF );
146  LOGF_ERROR( "Failed to connect to port %s. Error: %s", serialConnection->port(), errMsg );
147  return false;
148  }
149 
150  LOGF_INFO( "%s is online.", getDeviceName( ) );
151  return true;
152 }
153 
154 bool ShelyakDriver::Disconnect( )
155 {
156  if ( _serialPort != -1 )
157  {
158  tty_disconnect( _serialPort );
159  LOGF_INFO( "%s is offline.", getDeviceName( ) );
160  }
161 
162  clearProperties( );
163 
164  return true;
165 }
166 
167 /* Initialize and setup all properties on startup. */
168 bool ShelyakDriver::initProperties( )
169 {
171 
172  //--------------------------------------------------------------------------------
173  // Options
174  //--------------------------------------------------------------------------------
175  serialConnection = new Connection::Serial(this);
176  serialConnection->setDefaultPort("/dev/ttyACM0");
177  serialConnection->registerHandshake([&]()
178  {
179  return true;
180  });
181  registerConnection(serialConnection);
182 
183  // read the usis.json file
184  readConfig();
185 
187  return true;
188 }
189 
190 Action* ShelyakDriver::createAction( PropType type, const std::string &command )
191 {
192  Action* act = new Action( _guid++, command, type );
193  _actions.push_back( act );
194  return act;
195 }
196 
201 void ShelyakDriver::scanProperties( )
202 {
203  if( !_config.is_object() )
204  {
205  return;
206  }
207 
208  UsisResponse rsp;
209 
210  // ask the board name
211  if ( sendCmd( &rsp, "GET;DEVICE_NAME;VALUE" ) )
212  {
213 
214  // try to find dthe device definition in the .json
215  json device;
216  if( !findBoard( rsp.parts[4], &device ) )
217  {
218  LOGF_ERROR( "unknown device: %s", rsp.parts[4] );
219  fprintf( stderr, "device not found %s\n", rsp.parts[4] );
220  return;
221  }
222  else
223  {
224  LOGF_DEBUG( "found device: %s", rsp.parts[4] );
225  fprintf( stderr, "found device %s\n", rsp.parts[4] );
226 
227  // ok, found:
228  // enumerate categories and build properties
229 
230  json categs = device["categories"];
231  if( categs.is_object() )
232  {
233  for (json::iterator it = categs.begin(); it != categs.end(); ++it)
234  {
235  fprintf( stderr, "category %s\n", it.key().c_str() );
236  genCatProps( it.key().c_str(), it.value() );
237  }
238  }
239  }
240  }
241 
242 }
243 
248 void ShelyakDriver::genCatProps( const char* catName, json &category )
249 {
250 
251  //we scan different properties
252  if( !category.is_array() )
253  {
254  return;
255  }
256 
257  for ( auto it = category.begin(); it != category.end(); ++it)
258  {
259 
260  json item = *it;
261  if( !item.is_object( ) )
262  {
263  continue;
264  }
265 
266  json jname = item["name"];
267  if( !jname.is_string( ) )
268  {
269  LOGF_ERROR( "expected property name", "" );
270  continue;
271  }
272 
273  json jtype = item["type"];
274  if( !jtype.is_string() )
275  {
276  LOGF_ERROR( "expected property type", "" );
277  continue;
278  }
279 
280  json jcmd = item["command"];
281  if( !jcmd.is_string() )
282  {
283  LOGF_ERROR( "expected property command", "" );
284  continue;
285  }
286 
287  // we create a internal action
288 
289  Action* act;
290 
291  std::string name = jname;
292  std::string type = jtype;
293  std::string cmd = jcmd;
294 
295  fprintf( stderr, " name: %s\n", name.c_str() );
296 
297  // ------------------------------------------------------
298  if ( type == "string" )
299  {
300 
301  fprintf( stderr, " type: string\n" );
302 
303  act = createAction( _text, type.c_str() );
304 
305  TextValue &text = act->text;
306  IUFillText( &text._val, act->uid, cmd.c_str(), "" );
307  IUFillTextVector( &text._vec, &text._val, 1, getDeviceName( ), act->uid, name.c_str(), catName, IP_RW, 60, IPS_OK );
308 
309  defineProperty( &act->text._vec );
310  }
311  // ------------------------------------------------------
312  else if ( type == "enum" )
313  {
314 
315  fprintf( stderr, " type: enum\n" );
316 
317  json values = item["values"];
318  if( !values.is_array() )
319  {
320  LOGF_ERROR( "expected enum values", "" );
321  continue;
322  }
323 
324  act = createAction( _enum, cmd.c_str() );
325  EnumValue &enm = act->enm;
326 
327  ISwitch* sws = enm._vals;
328  unsigned nsw = 0;
329 
330  // allowed values
331  for (json::iterator it = values.begin(); it != values.end() && nsw < MAX_ENUMS; ++it, ++nsw)
332  {
333  json jvalue = (*it);
334 
335  if( jvalue.is_string() )
336  {
337  std::string value = jvalue;
338 
339  Action* sub_act = createAction( _eitm, cmd.c_str() );
340  sub_act->itm.parent = act;
341  sub_act->itm.index = nsw;
342  sub_act->itm.val = value;
343  IUFillSwitch( &sws[nsw], sub_act->uid, value.c_str(), ISS_OFF );
344  }
345  }
346 
347  IUFillSwitchVector( &enm._vec, sws, nsw, getDeviceName( ), act->uid, name.c_str(), catName, IP_RW, ISR_1OFMANY, 60,
348  IPS_OK );
349  defineProperty( &enm._vec );
350  }
351  // ------------------------------------------------------
352  else if ( type == "number" )
353  {
354 
355  fprintf( stderr, " type: number\n" );
356 
357  double minVal = -9999.0;
358  double maxVal = +9999.0;
359  double precVal = 0.01;
360 
361  // fix min / max
362  json min = item["min"];
363  if( min.is_number() )
364  {
365  minVal = min;
366  fprintf( stderr, " min: %lf\n", minVal );
367  }
368 
369  json max = item["max"];
370  if( max.is_number() )
371  {
372  maxVal = max;
373  fprintf( stderr, " max: %lf\n", maxVal );
374  }
375 
376  json prec = item["prec"];
377  if( prec.is_number() )
378  {
379  precVal = prec;
380  fprintf( stderr, " prec: %lf\n", precVal );
381  }
382 
383  act = createAction( _number, cmd );
384 
385  NumValue &num = act->num;
386  IUFillNumber( &num._val, act->uid, name.c_str(), "%.2f", minVal, maxVal, precVal, 0 );
387  IUFillNumberVector( &num._vec, &num._val, 1, getDeviceName( ), act->uid, name.c_str(), catName, IP_RW, 5, IPS_OK );
388 
389  defineProperty( &num._vec );
390 
391 
392  json actions = item["actions"];
393  if( actions.is_array() )
394  {
395  fprintf( stderr, " actions:\n" );
396 
397  uint32_t flags = 0;
398  for (json::iterator it = actions.begin(); it != actions.end(); ++it)
399  {
400 
401  json value = (*it);
402  if( value.is_string() )
403  {
404  std::string n = value;
405  if( n == "STOP" )
406  {
407  flags |= ACTION_STOP;
408  fprintf( stderr, " stop\n" );
409  }
410  else if( n == "CALIB" )
411  {
412  flags |= ACTION_CALIB;
413  fprintf( stderr, " calib\n" );
414  }
415  }
416  }
417 
418  if( flags )
419  {
420 
421  act = createAction( _enum, cmd );
422  EnumValue &enm = act->enm;
423 
424  ISwitch* sws = enm._vals;
425  unsigned nsw = 0;
426 
427  if( flags & ACTION_STOP )
428  {
429  Action* sub_act = createAction( _ecmd, "" );
430  sub_act->cmd.cmd = "STOP";
431  sub_act->cmd.name = cmd;
432  sub_act->cmd.parent = act;
433  IUFillSwitch( &sws[nsw++], sub_act->uid, "STOP", ISS_OFF );
434  }
435 
436  if( flags & ACTION_CALIB )
437  {
438  Action* sub_act = createAction( _ecmd, "" );
439  sub_act->cmd.cmd = "CALIB";
440  sub_act->cmd.name = cmd;
441  sub_act->cmd.parent = act;
442  IUFillSwitch( &sws[nsw++], sub_act->uid, "CALIB", ISS_OFF );
443  }
444 
445  IUFillSwitchVector( &enm._vec, sws, nsw, getDeviceName( ), act->uid, " ", catName, IP_RW, ISR_ATMOST1, 60, IPS_IDLE );
446  defineProperty( &enm._vec );
447  }
448  }
449  }
450  else
451  {
452  LOGF_ERROR( "bad property type %s", type.c_str() );
453  }
454  }
455 }
456 
461 void ShelyakDriver::__update( void* ptr )
462 {
463  ((ShelyakDriver*)ptr)->update( );
464 }
465 
467 {
468 
469  if ( isConnected( ) )
470  {
471  //fprintf( stderr, "updating --------------------------------------\n" );
472 
473  for( auto it = _actions.cbegin(); it != _actions.cend(); ++it )
474  {
475 
476  Action* p = (*it);
477  if( !(p->type & 0x10) )
478  {
479  continue;
480  }
481 
482  //fprintf( stderr, "test: %s\n", p->name );
483 
484  UsisResponse rsp;
485  if( sendCmd( &rsp, "GET;%s;VALUE", p->name.c_str() ) )
486  {
487 
488  if ( p->type == _text )
489  {
490  p->text._vec.s = strcmp( rsp.parts[3], "BUSY") == 0 ? IPS_BUSY : IPS_OK;
491 
492  p->text._vec.tp->text = rsp.parts[4];
493  IDSetText( &p->text._vec, NULL );
494  }
495  else if( p->type == _enum )
496  {
497  p->enm._vec.s = strcmp( rsp.parts[3], "BUSY") == 0 ? IPS_BUSY : IPS_OK;
498 
499  ISwitch* values = p->enm._vals;
500  for( int i = 0; i < p->enm._vec.nsp; i++ )
501  {
502  values[i].s = ISS_OFF;
503  }
504 
505  for( auto it2 = _actions.cbegin(); it2 != _actions.cend(); ++it2 )
506  {
507  Action* c = (*it2);
508  if( c->type == _eitm && c->itm.parent == p && c->itm.val == rsp.parts[4] )
509  {
510  values[c->itm.index].s = ISS_ON;
511  IDSetSwitch( &p->enm._vec, NULL );
512  break;
513  }
514  }
515  }
516  else if ( p->type == _number )
517  {
518  p->num._vec.s = strcmp( rsp.parts[3], "BUSY") == 0 ? IPS_BUSY : IPS_OK;
519 
520  double value = _atof( rsp.parts[4] );
521  p->num._vec.np->value = value;
522  IDSetNumber( &p->num._vec, NULL );
523  }
524  }
525  }
526 
527  IEAddTimer( 1000, __update, this );
528  }
529 }
530 
531 
532 
533 
534 // :: SERIAL ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
535 
536 
537 bool ShelyakDriver::sendCmd( UsisResponse* rsp, const char* text, ... )
538 {
539  va_list lst;
540  va_start( lst, text );
541 
542  bool rc = _send( text, lst ) && _receive( rsp );
543 
544  va_end( lst );
545  return rc;
546 }
547 
548 bool ShelyakDriver::_send( const char* text, va_list lst )
549 {
550  char buf[MAX_FRAME_LENGTH + 1];
551  vsnprintf( buf, MAX_FRAME_LENGTH, text, lst );
552 
553  //fprintf( stderr, "> sending %s\n", buf );
554  //LOGF_INFO("> sending %s", buf );
555 
556  strcat( buf, "\n" );
557 
558  int rc, nbytes_written;
559  if ( ( rc = tty_write( _serialPort, buf, strlen( buf ),
560  &nbytes_written ) ) != TTY_OK ) // send the bytes to the spectrograph
561  {
562  char errmsg[MAXRBUF];
563  tty_error_msg( rc, errmsg, MAXRBUF );
564  LOGF_ERROR("> sending %s", buf );
565  LOGF_ERROR( "error: %s.", errmsg );
566  return false;
567  }
568 
569  return true;
570 }
571 
572 bool ShelyakDriver::_receive( UsisResponse* rsp )
573 {
574  int rc, nread;
575  if ( ( rc = tty_nread_section( _serialPort, rsp->buffer, sizeof( rsp->buffer ), '\n', 100,
576  &nread ) ) != TTY_OK ) // send the bytes to the spectrograph
577  {
578  char errmsg[MAXRBUF];
579  tty_error_msg( rc, errmsg, MAXRBUF );
580  LOGF_ERROR( "error: %s.", errmsg );
581  return false;
582  }
583 
584  rsp->buffer[nread] = 0;
585 
586  fprintf( stderr, "< received %s\n", rsp->buffer );
587  //LOGF_INFO("< received %s", rsp->buffer );
588 
589  char* p = rsp->buffer;
590  char* e = p + nread;
591 
592  // trim '\n' & ' '
593  while ( e >= p && ( e[-1] == '\n' || e[-1] == ' ' ) )
594  {
595  e--;
596  *e = 0;
597  }
598 
599  rsp->pcount = 0;
600  rsp->parts[rsp->pcount++] = p;
601 
602  while ( p < e && rsp->pcount < 5 )
603  {
604  if ( *p == ';' )
605  {
606  *p = 0;
607  rsp->parts[rsp->pcount++] = p + 1;
608  }
609 
610  p++;
611  }
612 
613  if ( strcmp( rsp->parts[0], "M00" ) != 0 )
614  {
615  LOGF_ERROR( "response error: %s", rsp->parts[1] );
616  return false;
617  }
618 
619  return true;
620 }
621 
622 
623 // :: PROPERTIES ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
624 
625 
626 bool ShelyakDriver::updateProperties( )
627 {
629  if ( isConnected( ) )
630  {
631  //fprintf( stderr, "update request --------------------------------------\n" );
632  scanProperties( );
633  update( );
634  }
635  else
636  {
637  clearProperties( );
638  }
639 
640  return true;
641 }
642 
643 void ShelyakDriver::clearProperties( )
644 {
645  //fprintf( stderr, "clear properties --------------------------------------\n" );
646  for( auto it = _actions.cbegin(); it != _actions.cend(); ++it )
647  {
648  Action* p = *it;
649  deleteProperty( p->uid );
650  }
651 
652  _actions.clear();
653 }
654 
659 bool ShelyakDriver::ISNewSwitch( const char* dev, const char* name, ISState* states, char* names[], int n )
660 {
661  if ( dev && strcmp( dev, getDeviceName( ) ) == 0 )
662  {
663 
664  for( auto it = _actions.cbegin(); it != _actions.cend(); ++it )
665  {
666  Action* p = *it;
667 
668  if( p->type == _eitm && strcmp( p->uid, names[0] ) == 0 )
669  {
670  UsisResponse rsp;
671  sendCmd( &rsp, "SET;%s;VALUE;%s", p->name.c_str(), p->itm.val.c_str() );
672  return true;
673  }
674  else if( p->type == _ecmd && strcmp( p->uid, names[0] ) == 0 )
675  {
676  UsisResponse rsp;
677  sendCmd( &rsp, "%s;%s;", p->cmd.cmd.c_str(), p->cmd.name.c_str() );
678 
679  EnumValue &enm = p->cmd.parent->enm;
680  IUResetSwitch( &enm._vec );
681  enm._vec.s = IPS_IDLE;
682  IDSetSwitch(&enm._vec, nullptr);
683  return true;
684  }
685  }
686  }
687 
688  return INDI::DefaultDevice::ISNewSwitch( dev, name, states, names, n ); // send it to the parent classes
689 }
690 
695 bool ShelyakDriver::ISNewText( const char* dev, const char* name, char* texts[], char* names[], int n )
696 {
697  if ( dev && strcmp( dev, getDeviceName( ) ) == 0 )
698  {
699  for( auto it = _actions.cbegin(); it != _actions.cend(); ++it )
700  {
701  Action* p = *it;
702  if ( p->type == _text && strcmp( p->uid, names[0] ) == 0 )
703  {
704  UsisResponse rsp;
705  sendCmd( &rsp, "SET;%s;VALUE;%s", p->name.c_str(), texts[0] );
706  return true;
707  }
708  }
709  }
710 
711  return INDI::DefaultDevice::ISNewText( dev, name, texts, names, n );
712 }
713 
718 bool ShelyakDriver::ISNewNumber( const char* dev, const char* name, double values[], char* names[], int n )
719 {
720  if ( dev && strcmp( dev, getDeviceName( ) ) == 0 && n == 1 )
721  {
722 
723  for( auto it = _actions.cbegin(); it != _actions.cend(); ++it )
724  {
725  Action* p = *it;
726  if ( p->type == _number && strcmp( p->uid, names[0] ) == 0 )
727  {
728  UsisResponse rsp;
729  sendCmd( &rsp, "SET;%s;VALUE;%lf", p->name.c_str(), values[0] );
730  return true;
731  }
732  }
733  }
734 
735  return INDI::DefaultDevice::ISNewNumber( dev, name, values, names, n );
736 }
737 
738 
739 
hid_device * device
TextValue text
EnumItem itm
CmdItem cmd
char uid[8]
std::string name
NumValue num
EnumValue enm
PropType type
void registerHandshake(std::function< bool()> callback)
registerHandshake Register a handshake function to be called once the intial connection to the device...
The Serial class manages connection with serial devices including Bluetooth. Serial communication is ...
void setDefaultPort(const char *port)
setDefaultPort Set default port. Call this function in initProperties() of your driver if you want to...
virtual const char * port()
bool isConnected() const
Definition: basedevice.cpp:520
static std::string getSharedFilePath(std::string fileName)
Definition: basedevice.cpp:213
const char * getDeviceName() const
Definition: basedevice.cpp:821
virtual bool updateProperties()
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process the client newSwitch command.
void registerConnection(Connection::Interface *newConnection)
registerConnection Add new connection plugin to the existing connection pool. The connection type sha...
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
virtual bool initProperties()
Initilize properties initial state and value. The child class must implement this function.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
void setDriverInterface(uint16_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process the client newSwitch command.
bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
const char * getDefaultName() override
static void __update(void *ptr)
bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
a class to store JSON values
Definition: json.h:18647
constexpr bool is_object() const noexcept
return whether value is an object
Definition: json.h:19895
constexpr bool is_string() const noexcept
return whether value is a string
Definition: json.h:19909
constexpr bool is_array() const noexcept
return whether value is an array
Definition: json.h:19902
constexpr bool is_number() const noexcept
return whether value is a number
Definition: json.h:19867
general exception of the basic_json class
Definition: json.h:4032
a template for a bidirectional iterator for the basic_json class This class implements a both iterato...
Definition: json.h:12383
int IEAddTimer(int millisecs, IE_TCF *fp, void *p)
Register a new single-shot timer function, fp, to be called with ud as argument after ms.
Definition: eventloop.c:582
double max(void)
double min(void)
double _atof(const char *in)
#define SHELYAK_USIS_VERSION_MINOR
Definition: version.h:4
#define ACTION_CALIB
PropType
@ _number
@ _eitm
@ _ecmd
@ _text
@ _enum
#define ACTION_STOP
#define MAX_FRAME_LENGTH
#define MAX_ENUMS
ISState
Switch state.
Definition: indiapi.h:150
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
@ IP_RW
Definition: indiapi.h:186
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
@ ISR_1OFMANY
Definition: indiapi.h:173
@ ISR_ATMOST1
Definition: indiapi.h:174
int tty_connect(const char *device, int bit_rate, int word_size, int parity, int stop_bits, int *fd)
Establishes a tty connection to a terminal device.
Definition: indicom.c:946
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:424
int tty_disconnect(int fd)
Closes a tty connection and flushes the bus.
Definition: indicom.c:1148
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
int tty_nread_section(int fd, char *buf, int nsize, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition: indicom.c:666
Implementations for common driver routines.
@ TTY_OK
Definition: indicom.h:150
void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:272
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indidevapi.c:148
void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:291
void IUFillSwitch(ISwitch *sp, const char *name, const char *label, ISState s)
Assign attributes for a switch property. The switch's auxiliary elements will be set to NULL.
Definition: indidevapi.c:158
void IUFillText(IText *tp, const char *name, const char *label, const char *initialText)
Assign attributes for a text property. The text's auxiliary elements will be set to NULL.
Definition: indidevapi.c:198
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL.
Definition: indidevapi.c:180
void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char *dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s)
Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:235
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Definition: indidriver.c:1231
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
Definition: indidriver.c:1191
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
#define MAXRBUF
Definition: indiserver.cpp:102
@ value
the parser finished reading a JSON value
__le16 type
Definition: pwc-ioctl.h:0
__u8 cmd[4]
Definition: pwc-ioctl.h:2
Action * parent
std::string cmd
std::string name
Action * parent
std::string val
ISwitchVectorProperty _vec
ISwitch _vals[MAX_ENUMS]
One switch descriptor.
INumber _val
INumberVectorProperty _vec
ITextVectorProperty _vec
char buffer[MAX_FRAME_LENGTH]
#define SHELYAK_USIS_VERSION_MAJOR
Definition: version.h:3