/ adafruit_si4713.py
adafruit_si4713.py
1 # The MIT License (MIT) 2 # 3 # Copyright (c) 2017 Tony DiCola for Adafruit Industries 4 # 5 # Permission is hereby granted, free of charge, to any person obtaining a copy 6 # of this software and associated documentation files (the "Software"), to deal 7 # in the Software without restriction, including without limitation the rights 8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 # copies of the Software, and to permit persons to whom the Software is 10 # furnished to do so, subject to the following conditions: 11 # 12 # The above copyright notice and this permission notice shall be included in 13 # all copies or substantial portions of the Software. 14 # 15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 # THE SOFTWARE. 22 """ 23 `adafruit_si4713` 24 ==================================================== 25 26 CircuitPython module for the SI4713 RDS FM transmitter. See 27 examples/simpletest.py for a demo of the usage. Based on the Arduino library 28 at: https://github.com/adafruit/Adafruit-Si4713-Library/ 29 30 * Author(s): Tony DiCola 31 """ 32 import time 33 34 from micropython import const 35 import ustruct 36 37 import adafruit_bus_device.i2c_device as i2c_device 38 39 40 __version__ = "0.0.0-auto.0" 41 __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_SI4713.git" 42 43 44 #pylint: disable=bad-whitespace 45 # Internal constants: 46 _SI4710_ADDR0 = const(0x11) # if SEN is = const(low) 47 _SI4710_ADDR1 = const(0x63) # if SEN is high, default 48 _SI4710_STATUS_CTS = const(0x80) 49 _SI4710_CMD_POWER_UP = const(0x01) 50 _SI4710_CMD_GET_REV = const(0x10) 51 _SI4710_CMD_POWER_DOWN = const(0x11) 52 _SI4710_CMD_SET_PROPERTY = const(0x12) 53 _SI4710_CMD_GET_PROPERTY = const(0x13) 54 _SI4710_CMD_GET_INT_STATUS = const(0x14) 55 _SI4710_CMD_PATCH_ARGS = const(0x15) 56 _SI4710_CMD_PATCH_DATA = const(0x16) 57 _SI4710_CMD_TX_TUNE_FREQ = const(0x30) 58 _SI4710_CMD_TX_TUNE_POWER = const(0x31) 59 _SI4710_CMD_TX_TUNE_MEASURE = const(0x32) 60 _SI4710_CMD_TX_TUNE_STATUS = const(0x33) 61 _SI4710_CMD_TX_ASQ_STATUS = const(0x34) 62 _SI4710_CMD_TX_RDS_BUFF = const(0x35) 63 _SI4710_CMD_TX_RDS_PS = const(0x36) 64 _SI4710_CMD_TX_AGC_OVERRIDE = const(0x48) 65 _SI4710_CMD_GPO_CTL = const(0x80) 66 _SI4710_CMD_GPO_SET = const(0x81) 67 _SI4713_PROP_GPO_IEN = const(0x0001) 68 _SI4713_PROP_DIGITAL_INPUT_FORMAT = const(0x0101) 69 _SI4713_PROP_DIGITAL_INPUT_SAMPLE_RATE = const(0x0103) 70 _SI4713_PROP_REFCLK_FREQ = const(0x0201) 71 _SI4713_PROP_REFCLK_PRESCALE = const(0x0202) 72 _SI4713_PROP_TX_COMPONENT_ENABLE = const(0x2100) 73 _SI4713_PROP_TX_AUDIO_DEVIATION = const(0x2101) 74 _SI4713_PROP_TX_PILOT_DEVIATION = const(0x2102) 75 _SI4713_PROP_TX_RDS_DEVIATION = const(0x2103) 76 _SI4713_PROP_TX_LINE_LEVEL_INPUT_LEVEL = const(0x2104) 77 _SI4713_PROP_TX_LINE_INPUT_MUTE = const(0x2105) 78 _SI4713_PROP_TX_PREEMPHASIS = const(0x2106) 79 _SI4713_PROP_TX_PILOT_FREQUENCY = const(0x2107) 80 _SI4713_PROP_TX_ACOMP_ENABLE = const(0x2200) 81 _SI4713_PROP_TX_ACOMP_THRESHOLD = const(0x2201) 82 _SI4713_PROP_TX_ATTACK_TIME = const(0x2202) 83 _SI4713_PROP_TX_RELEASE_TIME = const(0x2203) 84 _SI4713_PROP_TX_ACOMP_GAIN = const(0x2204) 85 _SI4713_PROP_TX_LIMITER_RELEASE_TIME = const(0x2205) 86 _SI4713_PROP_TX_ASQ_INTERRUPT_SOURCE = const(0x2300) 87 _SI4713_PROP_TX_ASQ_LEVEL_LOW = const(0x2301) 88 _SI4713_PROP_TX_ASQ_DURATION_LOW = const(0x2302) 89 _SI4713_PROP_TX_AQS_LEVEL_HIGH = const(0x2303) 90 _SI4713_PROP_TX_AQS_DURATION_HIGH = const(0x2304) 91 _SI4713_PROP_TX_RDS_INTERRUPT_SOURCE = const(0x2C00) 92 _SI4713_PROP_TX_RDS_PI = const(0x2C01) 93 _SI4713_PROP_TX_RDS_PS_MIX = const(0x2C02) 94 _SI4713_PROP_TX_RDS_PS_MISC = const(0x2C03) 95 _SI4713_PROP_TX_RDS_PS_REPEAT_COUNT = const(0x2C04) 96 _SI4713_PROP_TX_RDS_MESSAGE_COUNT = const(0x2C05) 97 _SI4713_PROP_TX_RDS_PS_AF = const(0x2C06) 98 _SI4713_PROP_TX_RDS_FIFO_SIZE = const(0x2C07) 99 #pylint: enable=bad-whitespace 100 101 102 class SI4713: 103 """SI4713 RDS FM transmitter. Initialize by specifying: 104 - i2c: The I2C bus connected to the board. 105 106 Optionally specify: 107 - address: The I2C address if it has been changed. 108 - reset: A DigitalInOut instance connected to the board's reset line, 109 this will be used to perform a soft reset when necessary. 110 - timeout_s: The amount of time (in seconds) to wait for a command to 111 succeed. If this timeout is exceed a runtime error is thrown. 112 """ 113 114 # Class-level buffer to reduce allocations and heap fragmentation. 115 # This is not thread-safe or re-entrant by design! 116 _BUFFER = bytearray(10) 117 118 def __init__(self, i2c, *, address=_SI4710_ADDR1, reset=None, timeout_s=0.1): 119 self._timeout_s = timeout_s 120 self._device = i2c_device.I2CDevice(i2c, address) 121 # Configure reset line if it was provided. 122 self._reset = reset 123 if self._reset is not None: 124 self._reset.switch_to_output(value=True) 125 self.reset() 126 # Check product ID. 127 if self._get_product_number() != 13: 128 raise RuntimeError('Failed to find SI4713, check wiring!') 129 130 def _read_u8(self, address): 131 # Read an 8-bit unsigned value from the specified 8-bit address. 132 with self._device as i2c: 133 self._BUFFER[0] = address & 0xFF 134 i2c.write(self._BUFFER, end=1, stop=True) 135 i2c.readinto(self._BUFFER, end=1) 136 return self._BUFFER[0] 137 138 def _read_into(self, buf, count=None): 139 # Read data directly from the I2C bus into the specified buffer. If 140 # count is not provided the buffer will be filled, otherwise count bytes 141 # will be written to the buffer. 142 if count is None: 143 count = len(buf) 144 with self._device as i2c: 145 i2c.readinto(buf, end=count) 146 147 def _write_from(self, buf, count=None): 148 # Write a buffer of byte data to the chip. If count is not specified 149 # then the entire buffer is written, otherwise count bytes are written. 150 # This function will wait to verify the command was successfully 151 # sent/performed and if it fails to see success in the specified 152 # timeout (100ms by default) it will throw an exception. 153 if count is None: 154 count = len(buf) 155 # Send command. 156 with self._device as i2c: 157 i2c.write(buf, end=count, stop=True) 158 # Poll the status bit waiting for success or throwing a timeout error. 159 start = time.monotonic() 160 while True: 161 with self._device as i2c: 162 i2c.readinto(self._BUFFER, end=1) 163 if self._BUFFER[0] & _SI4710_STATUS_CTS > 0: 164 return 165 if time.monotonic() - start > self._timeout_s: 166 raise RuntimeError('Timeout waiting for SI4723 response, check wiring!') 167 168 def _set_property(self, prop, val): 169 # Set a property of the SI4713 chip. These are both 16-bit values. 170 self._BUFFER[0] = _SI4710_CMD_SET_PROPERTY 171 self._BUFFER[1] = 0 172 self._BUFFER[2] = prop >> 8 173 self._BUFFER[3] = prop & 0xFF 174 self._BUFFER[4] = val >> 8 175 self._BUFFER[5] = val & 0xFF 176 self._write_from(self._BUFFER, count=6) 177 178 def _get_product_number(self): 179 # Retrieve the product number/ID value of the chip and return it. 180 # First send a get revision command. 181 self._BUFFER[0] = _SI4710_CMD_GET_REV 182 self._BUFFER[1] = 0 183 self._write_from(self._BUFFER, count=2) 184 # Then read 9 bytes to get the response data and parse out pn. 185 with self._device as i2c: 186 i2c.readinto(self._BUFFER, end=9) 187 return self._BUFFER[1] 188 # Other potentially useful but unused data: 189 #fw = (self._BUFFER[2] << 8) | self._BUFFER[3] 190 #patch = (self._BUFFER[4] << 8) | self._BUFFER[5] 191 #cmp = (self._BUFFER[6] << 8) | self._BUFFER[7] 192 #rev = (self._BUFFER[8]) 193 194 def reset(self): 195 """Perform a reset of the chip using the reset line. Will also 196 perform necessary chip power up procedures.""" 197 # Toggle reset low for a few milliseconds if the line was provided. 198 if self._reset is not None: 199 # Toggle reset line low for a few milliseconds to reset the chip. 200 self._reset.value = True 201 time.sleep(0.01) 202 self._reset.value = False 203 time.sleep(0.01) 204 self._reset.value = True 205 # Next perform all the chip power up procedures. 206 self._BUFFER[0] = _SI4710_CMD_POWER_UP 207 self._BUFFER[1] = 0x12 208 # CTS interrupt disabled 209 # GPO2 output disabled 210 # Boot normally 211 # xtal oscillator ENabled 212 # FM transmit 213 self._BUFFER[2] = 0x50 # analog input mode 214 self._write_from(self._BUFFER, count=3) 215 # configuration! see datasheet page 254 216 # crystal is 32.768 217 self._set_property(_SI4713_PROP_REFCLK_FREQ, 32768) 218 # 74uS pre-emph (USA std) 219 self._set_property(_SI4713_PROP_TX_PREEMPHASIS, 0) 220 # max gain? 221 self._set_property(_SI4713_PROP_TX_ACOMP_GAIN, 10) 222 # turn on limiter and AGC 223 self._set_property(_SI4713_PROP_TX_ACOMP_ENABLE, 0x0) 224 225 @property 226 def interrupt_status(self): 227 """Read the interrupt bit status of the chip. This will return a byte 228 value with interrupt status bits as defined by the radio, see page 229 11 of the AN332 programming guide: 230 https://www.silabs.com/documents/public/application-notes/AN332.pdf 231 """ 232 return self._read_u8(_SI4710_CMD_GET_INT_STATUS) 233 234 def _poll_interrupt_status(self, expected): 235 # Poll the interrupt status bit for an expected exact value. 236 # Will throw an exception if the timeout is exceeded before the status 237 # reaches the desired value. 238 start = time.monotonic() 239 while self.interrupt_status != expected: 240 time.sleep(0.01) # Short delay for other processing. 241 if time.monotonic() - start > self._timeout_s: 242 raise RuntimeError('Timeout waiting for SI4713 to respond!') 243 244 def _tune_status(self): 245 # Retrieve the tune status command values from the radio. Will store 246 # the raw result of the tune status command in self._BUFFER (see page 247 # 22 of AN332). 248 # Construct tune status command and send it. 249 self._BUFFER[0] = _SI4710_CMD_TX_TUNE_STATUS 250 self._BUFFER[1] = 0x01 251 self._write_from(self._BUFFER, count=2) 252 # Now read 8 bytes of response data. 253 self._read_into(self._BUFFER, count=8) 254 255 def _asq_status(self): 256 # Retrieve the ASQ (audio signal quality) status from the chip. Will 257 # store the raw result of the ASQ status command in self._BUFFER (see 258 # page 25 of AN332). 259 # Construct ASQ status command and send it. 260 self._BUFFER[0] = _SI4710_CMD_TX_ASQ_STATUS 261 self._BUFFER[1] = 0x01 262 self._write_from(self._BUFFER, count=2) 263 # Now read 5 bytes of response data. 264 self._read_into(self._BUFFER, count=5) 265 266 @property 267 def tx_frequency_khz(self): 268 """Get and set the transmit frequency of the chip (in kilohertz). See 269 AN332 page 19 for a discussion of the constraints on this value, in 270 particular only a multiple of 50khz can be specified, and the value 271 must be between 76 and 108mhz. 272 """ 273 self._tune_status() 274 # Reconstruct frequency from tune status response. 275 frequency = (self._BUFFER[2] << 8) | self._BUFFER[3] 276 # Return result, scaling back to khz from 10's of khz. 277 return frequency * 10 278 279 @tx_frequency_khz.setter 280 def tx_frequency_khz(self, val): 281 assert 76000 <= val <= 108000 282 assert (val % 50) == 0 283 # Convert to units of 10khz that chip expects. 284 val = (val // 10) & 0xFFFF 285 # Construct tune command. 286 self._BUFFER[0] = _SI4710_CMD_TX_TUNE_FREQ 287 self._BUFFER[1] = 0 288 self._BUFFER[2] = val >> 8 289 self._BUFFER[3] = val & 0xFF 290 self._write_from(self._BUFFER, count=4) 291 # Wait for the CTS and tune complete bits to be set. 292 self._poll_interrupt_status(0x81) 293 294 @property 295 def tx_power(self): 296 """Get and set the transmit power in dBuV (decibel microvolts). Can 297 be a value within the range of 88-115, or 0 to indicate transmission 298 power is disabled. Setting this value assumes auto-tuning of antenna 299 capacitance, see the set_tx_power_capacitance function for explicit 300 control of setting both transmit power and capacitance if needed. 301 """ 302 self._tune_status() 303 # Reconstruct power from tune status response and return it. 304 return self._BUFFER[5] 305 306 def set_tx_power_capacitance(self, tx_power, capacitance): 307 """Set both the transmit power (in dBuV, from 88-115) and antenna 308 capacitance of the transmitter. Capacitance is a value specified in 309 pF from 0.25 to 47.75 (in 0.25 steps), or 0 to indicate automatic 310 tuning. You typically don't need to use this function unless you want 311 explicit control of tuning antenna capacitance, instead for simple 312 transmit power changes use the tx_power property (which assumes 313 automatic antenna capacitance). 314 """ 315 # Validate tx power and capacitance are in allowed range. 316 assert tx_power == 0 or (88 <= tx_power <= 115) 317 assert capacitance == 0 or (0.25 <= capacitance <= 47.75) 318 # Convert capacitance to 0.25 pF units that chip expects. 319 capacitance = int(capacitance / 0.25) 320 # Construct a tune power command and send it. 321 self._BUFFER[0] = _SI4710_CMD_TX_TUNE_POWER 322 self._BUFFER[1] = 0 323 self._BUFFER[2] = 0 324 self._BUFFER[3] = tx_power & 0xFF 325 self._BUFFER[4] = capacitance & 0xFF 326 self._write_from(self._BUFFER, count=5) 327 328 @tx_power.setter 329 def tx_power(self, val): 330 # Assume automatic antenna capacitance tuning (0 value). 331 self.set_tx_power_capacitance(val, 0) 332 333 @property 334 def tx_antenna_capacitance(self): 335 """Read the transmit antenna capacitance in pico-Farads (pF). Use the 336 set_tx_power_capacitance function to change this value (must also 337 change transmit power at the same time). It's uncommon to adjust this 338 beyond the automatic tuning option! 339 """ 340 self._tune_status() 341 # Reconstruct capacitance from tune status response and return it 342 # (scaled appropriately for pF units). 343 return self._BUFFER[6] * 0.25 344 345 def received_noise_level(self, frequency_khz, antenna_capacitance=0): 346 """Measure the received noise level for the specified frequency (in 347 kilohertz, 76mhz - 108mhz and must be a multiple of 50) and return its 348 value in units of dBuV (decibel microvolts). Will use automatic 349 antenna capacitance tuning by default, otherwise specify an antenna 350 capacitance in pF from 0.25 to 47.75 (only steps of 0.25pF are 351 supported). 352 """ 353 # Validate frequency and capacitance. 354 assert 76000 <= frequency_khz <= 108000 355 assert (frequency_khz % 50) == 0 356 assert antenna_capacitance == 0 or \ 357 (0.25 <= antenna_capacitance <= 47.75) 358 # Convert frequency and capacitance to units used by the chip. 359 frequency_khz = (frequency_khz // 10) & 0xFFFF 360 antenna_capacitance = int(antenna_capacitance / 0.25) 361 # First send a read tune measure command to kick off the measurement. 362 self._BUFFER[0] = _SI4710_CMD_TX_TUNE_MEASURE 363 self._BUFFER[1] = 0 364 self._BUFFER[2] = frequency_khz >> 8 365 self._BUFFER[3] = frequency_khz & 0xFF 366 self._BUFFER[4] = antenna_capacitance 367 self._write_from(self._BUFFER, count=5) 368 # Wait for CTS and tune measure complete bits to be set. 369 self._poll_interrupt_status(0x81) 370 # Finally make a request for tune status and grab the received noise 371 # level value now that it's up to date. 372 self._tune_status() 373 return self._BUFFER[7] 374 375 @property 376 def input_level(self): 377 """Read the input level of audio to the chip and return it in dBfs 378 units. 379 """ 380 # Perform ASQ request, then parse out 8 bit _signed_ input level value. 381 self._asq_status() 382 return ustruct.unpack('bbbbb', self._BUFFER)[4] 383 384 @property 385 def audio_signal_status(self): 386 """Retrieve the ASQ or audio signal quality status value from the chip. 387 This is a byte that indicates if the transmitted input audio signal is 388 overmodulating (too high) or above/below input audio level thresholds. 389 See page 25 of AN332 for more discussion of this value: 390 https://www.silabs.com/documents/public/application-notes/AN332.pdf 391 """ 392 # Perform ASQ request, the parse out the status byte. 393 self._asq_status() 394 return self._BUFFER[1] 395 396 def gpio_control(self, gpio1=False, gpio2=False, gpio3=False): 397 """Control the GPIO outputs of the chip. Each gpio1, gpio2, gpio3 398 parameter is a boolean that indicates if that GPIO channel 399 (corresponding to GPIO1, GPIO2, GPIO3 of the chip respectively) is 400 driven actively (True) or is high-impedence/off (False). By default 401 any unspecified GPIO is set to high-impedence/off unless otherwise 402 provided. 403 """ 404 # Construct GPIO control state and send a GPIO control command. 405 control = 0x00 406 if gpio1: 407 control |= 0b00000010 408 if gpio2: 409 control |= 0b00000100 410 if gpio3: 411 control |= 0b00001000 412 self._BUFFER[0] = _SI4710_CMD_GPO_CTL 413 self._BUFFER[1] = control 414 self._write_from(self._BUFFER, count=2) 415 416 def gpio_set(self, gpio1=False, gpio2=False, gpio3=False): 417 """Drive the GPIO outputs of the chip that are enabled with active 418 output. Each gpio1, gpio2, gpio3 parameter is a boolean that indicates 419 if the associated GPIO (corresponding to GPIO1, GPIO2, GPIO3 of the 420 chip respectively) is driven high (True) or low (False). By default 421 all GPIO are assumed to be set low (False) unless otherwise 422 specified. Note that you must first set GPIOs to active output with 423 the gpio_control function to see their output physically change. 424 """ 425 # Construct GPIO set command and send it. 426 set_command = 0x00 427 if gpio1: 428 set_command |= 0b00000010 429 if gpio2: 430 set_command |= 0b00000100 431 if gpio3: 432 set_command |= 0b00001000 433 self._BUFFER[0] = _SI4710_CMD_GPO_SET 434 self._BUFFER[1] = set_command 435 self._write_from(self._BUFFER, count=2) 436 437 def _set_rds_station(self, station): 438 # Set the RDS station broadcast value. 439 station_length = len(station) 440 assert 0 <= station_length <= 96 441 self._BUFFER[0] = _SI4710_CMD_TX_RDS_PS 442 # Fire off each 4 byte update of the station value. 443 for i in range(0, station_length, 4): 444 self._BUFFER[1] = i // 4 445 self._BUFFER[2] = station[i] if i < station_length else ' ' 446 self._BUFFER[3] = station[i+1] if i+1 < station_length else ' ' 447 self._BUFFER[4] = station[i+2] if i+2 < station_length else ' ' 448 self._BUFFER[5] = station[i+3] if i+3 < station_length else ' ' 449 self._write_from(self._BUFFER, count=6) 450 451 def _set_rds_buffer(self, rds_buffer): 452 # Set the RDS buffer broadcast value. 453 buf_length = len(rds_buffer) 454 # 53 blocks in the circular buffer, each 2 bytes long. 455 assert 0 <= buf_length <= 106 456 self._BUFFER[0] = _SI4710_CMD_TX_RDS_BUFF 457 self._BUFFER[1] = 0x06 # Clear the buffer and start update with first 458 # request, then future requests will turn off 459 # the empty bit to continue setting data. 460 self._BUFFER[2] = 0x20 461 # Fire off each 4 byte update of the station value. 462 for i in range(0, buf_length, 4): 463 self._BUFFER[3] = i // 4 464 self._BUFFER[4] = rds_buffer[i] if i < buf_length else ' ' 465 self._BUFFER[5] = rds_buffer[i+1] if i+1 < buf_length else ' ' 466 self._BUFFER[6] = rds_buffer[i+2] if i+2 < buf_length else ' ' 467 self._BUFFER[7] = rds_buffer[i+3] if i+3 < buf_length else ' ' 468 self._write_from(self._BUFFER, count=8) 469 # Make sure to turn off empty bit for next requests. 470 self._BUFFER[1] = 0x04 471 472 rds_station = property(None, _set_rds_station, None, 473 """Set the RDS broadcast station to the specified 474 byte string. Can be at most 96 bytes long and will 475 be padded with blank spaces if less. 476 """) 477 478 rds_buffer = property(None, _set_rds_buffer, None, 479 """Set the RDS broadcast buffer to the specified byte 480 string. Can be at most 106 bytes long and will be 481 padded with blank spaces if less. 482 """) 483 484 def configure_rds(self, program_id, station=None, rds_buffer=None): 485 """Configure and enable the RDS broadcast of the specified program ID. 486 Program ID must be a 16-bit value that will be broacast on the RDS 487 bands of the transmitter. Specify optional station and RDS buffer 488 strings that will be used to broadcast the station and currently 489 playing song information, or later set the rds_station and 490 rds_buffer to change these values too. The station value is up to 96 491 bytes long, and the buffer is up to 106 bytes long. Note this will 492 configure RDS properties of the chip for a typical North American RDS 493 broadcast (deviation, mix, repeat, etc. parameters). 494 """ 495 assert 0 <= program_id <= 65535 496 # Set RDS parameters: 497 # 66.25KHz (default is 68.25) 498 self._set_property(_SI4713_PROP_TX_AUDIO_DEVIATION, 6625) 499 # 2KHz (default) 500 self._set_property(_SI4713_PROP_TX_RDS_DEVIATION, 200) 501 # RDS IRQ 502 self._set_property(_SI4713_PROP_TX_RDS_INTERRUPT_SOURCE, 0x0001) 503 # program identifier 504 self._set_property(_SI4713_PROP_TX_RDS_PI, program_id) 505 # 50% mix (default) 506 self._set_property(_SI4713_PROP_TX_RDS_PS_MIX, 0x03) 507 # RDSD0 & RDSMS (default) 508 self._set_property(_SI4713_PROP_TX_RDS_PS_MISC, 0x1808) 509 # 3 repeats (default) 510 self._set_property(_SI4713_PROP_TX_RDS_PS_REPEAT_COUNT, 3) 511 self._set_property(_SI4713_PROP_TX_RDS_MESSAGE_COUNT, 1) 512 # no AF 513 self._set_property(_SI4713_PROP_TX_RDS_PS_AF, 0xE0E0) 514 self._set_property(_SI4713_PROP_TX_RDS_FIFO_SIZE, 0) 515 self._set_property(_SI4713_PROP_TX_COMPONENT_ENABLE, 0x0007) 516 # Set station and buffer to initial values if specified. 517 if station is not None: 518 self._set_rds_station(station) 519 if rds_buffer is not None: 520 self._set_rds_buffer(rds_buffer)